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"
35 static inline jit_type_t
psi_jit_decl_arg_type(struct psi_decl_arg
*darg
);
37 static inline jit_abi_t
psi_jit_abi(const char *convention
)
41 static inline jit_type_t
psi_jit_token_type(token_t t
)
50 return jit_type_sbyte
;
52 return jit_type_ubyte
;
54 return jit_type_short
;
56 return jit_type_ushort
;
64 return jit_type_ulong
;
66 return jit_type_sys_bool
;
69 return jit_type_sys_int
;
71 return jit_type_sys_long
;
73 return jit_type_sys_float
;
75 return jit_type_sys_double
;
76 #ifdef HAVE_LONG_DOUBLE
77 case PSI_T_LONG_DOUBLE
:
78 return jit_type_sys_long_double
;
82 return jit_type_void_ptr
;
85 static inline jit_type_t
psi_jit_impl_type(token_t impl_type
)
89 return jit_type_sbyte
;
93 return jit_type_void_ptr
;
96 return jit_type_sys_double
;
97 EMPTY_SWITCH_DEFAULT_CASE()
103 static void psi_jit_struct_type_dtor(void *type
)
105 jit_type_t strct
= type
;
107 jit_type_free(strct
);
110 static size_t psi_jit_struct_type_pad(jit_type_t
*els
, size_t padding
)
114 for (i
= 0; i
< padding
; ++i
) {
115 *els
++ = jit_type_copy(jit_type_sys_char
);
121 static unsigned psi_jit_struct_type_elements(struct psi_decl_struct
*strct
,
124 size_t i
= 0, argc
= psi_plist_count(strct
->args
), nels
= 0, offset
= 0,
126 struct psi_decl_arg
*darg
;
128 *fields
= calloc(argc
+ 1, sizeof(*fields
));
130 while (psi_plist_get(strct
->args
, i
++, &darg
)) {
131 jit_type_t type
= jit_type_copy(psi_jit_decl_arg_type(darg
));
132 size_t padding
, alignment
;
134 if ((alignment
= jit_type_get_alignment(type
)) > maxalign
) {
135 maxalign
= alignment
;
138 assert(jit_type_get_size(type
) == darg
->layout
->len
);
139 if ((padding
= psi_offset_padding(darg
->layout
->pos
- offset
, alignment
))) {
140 if (nels
+ padding
> argc
) {
142 *fields
= realloc(*fields
, (argc
+ 1) * sizeof(*fields
));
144 psi_jit_struct_type_pad(&(*fields
)[nels
], padding
);
148 assert(offset
== darg
->layout
->pos
);
150 offset
= (offset
+ darg
->layout
->len
+ alignment
- 1)
152 (*fields
)[nels
++] = type
;
155 /* apply struct alignment padding */
156 offset
= (offset
+ maxalign
- 1) & ~(maxalign
- 1);
158 ZEND_ASSERT(offset
<= strct
->size
);
159 if (offset
< strct
->size
) {
160 nels
+= psi_jit_struct_type_pad(&(*fields
)[nels
], strct
->size
- offset
);
165 static inline jit_type_t
psi_jit_decl_type(struct psi_decl_type
*type
)
167 struct psi_decl_type
*real
= psi_decl_type_get_real(type
);
169 switch (real
->type
) {
171 if (!real
->real
.strct
->engine
.type
) {
173 jit_type_t strct
, *fields
= NULL
;
175 count
= psi_jit_struct_type_elements(real
->real
.strct
, &fields
);
176 strct
= jit_type_create_struct(fields
, count
, 0);
178 real
->real
.strct
->engine
.type
= strct
;
179 real
->real
.strct
->engine
.dtor
= psi_jit_struct_type_dtor
;
182 return real
->real
.strct
->engine
.type
;
186 struct psi_decl_arg
*arg
;
187 psi_plist_get(real
->real
.unn
->args
, 0, &arg
);
188 return psi_jit_decl_arg_type(arg
);
192 return psi_jit_token_type(real
->type
);
195 static inline jit_type_t
psi_jit_decl_arg_type(struct psi_decl_arg
*darg
)
197 if (darg
->var
->pointer_level
) {
198 return jit_type_void_ptr
;
200 return psi_jit_decl_type(darg
->type
);
204 struct psi_jit_context
{
206 jit_type_t signature
;
209 struct psi_jit_call
{
210 struct psi_context
*context
;
213 struct psi_impl
*impl
;
214 struct psi_call_frame
*frame
;
217 struct psi_let_exp
*let_exp
;
218 struct psi_jit_call
*impl_call
;
222 jit_type_t signature
;
223 void *params
[1]; /* [type1, type2, ... ] */
226 static void psi_jit_handler(jit_type_t sig
, void *result
, void **args
, void *data
)
228 struct psi_jit_call
*call
= data
;
230 psi_context_call(call
->context
, *(zend_execute_data
**)args
[0], *(zval
**) args
[1], call
->impl
.fn
.impl
);
233 static void psi_jit_callback(jit_type_t sig
, void *result
, void **args
,
236 struct psi_jit_call
*call
= data
, *impl_call
= call
->impl
.cb
.impl_call
;
237 struct psi_call_frame_callback cbdata
;
239 cbdata
.cb
= call
->impl
.cb
.let_exp
;
240 cbdata
.argc
= jit_type_num_params(sig
);
242 cbdata
.rval
= result
;
244 psi_call_frame_do_callback(impl_call
->impl
.fn
.frame
, &cbdata
);
247 static inline struct psi_jit_call
*psi_jit_call_alloc(struct psi_context
*C
,
248 struct psi_decl
*decl
)
250 size_t i
, c
= psi_plist_count(decl
->args
);
251 struct psi_jit_call
*call
= calloc(1, sizeof(*call
) + 2 * c
* sizeof(void *));
252 struct psi_decl_arg
*arg
;
256 for (i
= 0; psi_plist_get(decl
->args
, i
, &arg
); ++i
) {
257 call
->params
[i
] = psi_jit_decl_arg_type(arg
);
259 call
->params
[c
] = NULL
;
261 call
->signature
= jit_type_create_signature(
262 psi_jit_abi(decl
->abi
->convention
),
263 psi_jit_decl_arg_type(decl
->func
),
264 (jit_type_t
*) call
->params
,
266 assert(call
->signature
);
271 static inline void *psi_jit_call_init_closure(struct psi_context
*C
,
272 struct psi_jit_call
*call
, struct psi_impl
*impl
)
274 struct psi_jit_context
*context
= C
->context
;
276 call
->impl
.fn
.impl
= impl
;
277 return call
->closure
= jit_closure_create(context
->jit
, context
->signature
,
278 &psi_jit_handler
, call
);
281 static inline void *psi_jit_call_init_callback_closure(struct psi_context
*C
,
282 struct psi_jit_call
*call
, struct psi_jit_call
*impl_call
,
283 struct psi_let_exp
*cb
)
285 struct psi_jit_context
*context
= C
->context
;
287 call
->impl
.cb
.let_exp
= cb
;
288 call
->impl
.cb
.impl_call
= impl_call
;
290 return call
->closure
= jit_closure_create(context
->jit
, call
->signature
,
291 &psi_jit_callback
, call
);
294 static inline void psi_jit_call_free(struct psi_jit_call
*call
)
296 jit_type_free(call
->signature
);
300 static inline struct psi_jit_context
*psi_jit_context_init(
301 struct psi_jit_context
*L
)
303 jit_type_t params
[] = {jit_type_void_ptr
, jit_type_void_ptr
};
306 L
= malloc(sizeof(*L
));
308 memset(L
, 0, sizeof(*L
));
310 L
->jit
= jit_context_create();
311 L
->signature
= jit_type_create_signature(jit_abi_cdecl
, jit_type_void
,
317 static inline void psi_jit_context_dtor(struct psi_jit_context
*L
)
319 jit_type_free(L
->signature
);
320 jit_context_destroy(L
->jit
);
323 static inline void psi_jit_context_free(struct psi_jit_context
**L
)
326 psi_jit_context_dtor(*L
);
332 static void psi_jit_init(struct psi_context
*C
)
334 C
->context
= psi_jit_context_init(NULL
);
337 static inline void psi_jit_destroy_callbacks(struct psi_context
*C
,
338 struct psi_let_exp
*let_exp
)
340 struct psi_let_callback
*cb
;
341 struct psi_let_func
*fn
= NULL
;
343 switch (let_exp
->kind
) {
344 case PSI_LET_CALLBACK
:
345 cb
= let_exp
->data
.callback
;
347 if (cb
->decl
&& cb
->decl
->info
) {
348 psi_jit_call_free(cb
->decl
->info
);
354 fn
= let_exp
->data
.func
;
359 struct psi_let_exp
*inner_let
;
361 while (psi_plist_get(fn
->inner
, i
++, &inner_let
)) {
362 psi_jit_destroy_callbacks(C
, inner_let
);
371 static void psi_jit_dtor(struct psi_context
*C
)
375 struct psi_decl
*decl
;
377 while (psi_plist_get(C
->decls
, i
++, &decl
)) {
379 psi_jit_call_free(decl
->info
);
385 struct psi_impl
*impl
;
387 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
389 struct psi_let_stmt
*let
;
391 while (psi_plist_get(impl
->stmts
.let
, l
++, &let
)) {
392 psi_jit_destroy_callbacks(C
, let
->exp
);
396 psi_jit_context_free((void *) &C
->context
);
399 static inline void psi_jit_compile_callbacks(struct psi_context
*C
,
400 struct psi_jit_call
*impl_call
, struct psi_let_exp
*let_exp
)
402 struct psi_jit_call
*call
;
403 struct psi_let_callback
*cb
;
404 struct psi_let_func
*fn
= NULL
;
406 switch (let_exp
->kind
) {
407 case PSI_LET_CALLBACK
:
408 cb
= let_exp
->data
.callback
;
409 if ((call
= psi_jit_call_alloc(C
, cb
->decl
))) {
410 if (!psi_jit_call_init_callback_closure(C
, call
, impl_call
, let_exp
)) {
411 psi_jit_call_free(call
);
415 cb
->decl
->sym
= call
->closure
;
421 fn
= let_exp
->data
.func
;
425 struct psi_let_exp
*inner_let
;
427 while (psi_plist_get(fn
->inner
, i
++, &inner_let
)) {
428 psi_jit_compile_callbacks(C
, impl_call
, inner_let
);
437 static zend_function_entry
*psi_jit_compile(struct psi_context
*C
)
439 size_t i
= 0, d
= 0, nf
= 0;
440 struct psi_impl
*impl
;
441 struct psi_decl
*decl
;
442 zend_function_entry
*zfe
;
443 struct psi_jit_context
*ctx
= C
->context
;
449 zfe
= calloc(psi_plist_count(C
->impls
) + 1, sizeof(*zfe
));
450 jit_context_build_start(ctx
->jit
);
452 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
453 zend_function_entry
*zf
= &zfe
[nf
];
454 struct psi_jit_call
*call
;
456 struct psi_let_stmt
*let
;
461 if (!(call
= psi_jit_call_alloc(C
, impl
->decl
))) {
464 if (!psi_jit_call_init_closure(C
, call
, impl
)) {
465 psi_jit_call_free(call
);
469 zf
->fname
= impl
->func
->name
+ (impl
->func
->name
[0] == '\\');
470 zf
->handler
= call
->closure
;
471 zf
->num_args
= psi_plist_count(impl
->func
->args
);
472 zf
->arg_info
= psi_internal_arginfo(impl
);
475 while (psi_plist_get(impl
->stmts
.let
, l
++, &let
)) {
476 psi_jit_compile_callbacks(C
, call
, let
->exp
);
480 while (psi_plist_get(C
->decls
, d
++, &decl
)) {
485 psi_jit_call_alloc(C
, decl
);
488 jit_context_build_end(ctx
->jit
);
493 static void psi_jit_call(struct psi_context
*C
, struct psi_call_frame
*frame
,
494 struct psi_decl
*decl
, void *rval
, void **args
)
496 struct psi_jit_call
*call
= decl
->info
;
497 struct psi_call_frame
*prev
= call
->impl
.fn
.frame
;
499 call
->impl
.fn
.frame
= frame
;
500 jit_apply(call
->signature
, decl
->sym
, args
, psi_plist_count(decl
->args
), rval
);
501 call
->impl
.fn
.frame
= prev
;
504 static void psi_jit_call_va(struct psi_context
*C
, struct psi_call_frame
*frame
,
505 struct psi_decl
*decl
, void *rval
, void **args
, size_t va_count
,
508 struct psi_jit_call
*info
= decl
->info
;
509 struct psi_call_frame
*prev
= info
->impl
.fn
.frame
;
510 size_t argc
= psi_plist_count(decl
->args
);
511 jit_type_t signature
;
512 jit_type_t
*param_types
= ecalloc(argc
+ va_count
+ 1, sizeof(jit_type_t
));
514 memcpy(param_types
, info
->params
, argc
* sizeof(jit_type_t
));
515 memcpy(param_types
+ argc
, va_types
, va_count
* sizeof(jit_type_t
));
517 signature
= jit_type_create_signature(jit_abi_vararg
,
518 jit_type_get_return(info
->signature
), param_types
, argc
+ va_count
,
520 ZEND_ASSERT(signature
);
522 info
->impl
.fn
.frame
= frame
;
523 jit_apply(signature
, decl
->sym
, args
, argc
, rval
);
524 info
->impl
.fn
.frame
= prev
;
525 jit_type_free(signature
);
529 static void *psi_jit_query(struct psi_context
*C
, enum psi_context_query q
,
533 case PSI_CONTEXT_QUERY_SELF
:
535 case PSI_CONTEXT_QUERY_TYPE
:
536 return psi_jit_impl_type(*(token_t
*) arg
);
541 static struct psi_context_ops ops
= {psi_jit_init
, psi_jit_dtor
,
542 psi_jit_compile
, psi_jit_call
, psi_jit_call_va
, psi_jit_query
};
544 struct psi_context_ops
*psi_libjit_ops(void)
549 #endif /* HAVE_LIBJIT */