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
)
39 if (!strcasecmp(convention
, "stdcall")) {
40 return jit_abi_stdcall
;
42 if (!strcasecmp(convention
, "fastcall")) {
43 return jit_abi_fastcall
;
47 static inline jit_type_t
psi_jit_token_type(token_t t
)
56 return jit_type_sbyte
;
58 return jit_type_ubyte
;
60 return jit_type_short
;
62 return jit_type_ushort
;
70 return jit_type_ulong
;
72 return jit_type_sys_bool
;
75 return jit_type_sys_int
;
77 return jit_type_sys_long
;
79 return jit_type_sys_float
;
81 return jit_type_sys_double
;
82 #ifdef HAVE_LONG_DOUBLE
83 case PSI_T_LONG_DOUBLE
:
84 return jit_type_sys_long_double
;
88 return jit_type_void_ptr
;
91 static inline jit_type_t
psi_jit_impl_type(token_t impl_type
)
95 return jit_type_sbyte
;
99 return jit_type_void_ptr
;
102 return jit_type_sys_double
;
103 EMPTY_SWITCH_DEFAULT_CASE()
109 struct psi_jit_struct_type
{
114 static void psi_jit_struct_type_dtor(void *ptr
)
116 struct psi_jit_struct_type
*type
= ptr
;
117 jit_type_t strct
= type
->strct
;
118 unsigned i
, n
= jit_type_num_fields(strct
);
120 for (i
= 0; i
< n
; ++i
) {
121 jit_type_t field
= jit_type_get_field(strct
, i
);
123 jit_type_free(field
);
125 jit_type_free(strct
);
130 static size_t psi_jit_struct_type_pad(jit_type_t
*els
, size_t padding
)
134 for (i
= 0; i
< padding
; ++i
) {
135 *els
++ = jit_type_copy(jit_type_sys_char
);
141 static unsigned psi_jit_struct_type_elements(struct psi_decl_struct
*strct
,
144 size_t i
= 0, argc
= psi_plist_count(strct
->args
), nels
= 0, offset
= 0,
145 maxalign
= 0, last_arg_pos
= -1;
146 struct psi_decl_arg
*darg
;
148 *fields
= calloc(argc
+ 1, sizeof(*fields
));
150 while (psi_plist_get(strct
->args
, i
++, &darg
)) {
152 size_t padding
, alignment
;
154 if (darg
->layout
->pos
== last_arg_pos
) {
155 /* skip bit fields */
158 last_arg_pos
= darg
->layout
->pos
;
160 type
= jit_type_copy(psi_jit_decl_arg_type(darg
));
162 if ((alignment
= jit_type_get_alignment(type
)) > maxalign
) {
163 maxalign
= alignment
;
166 assert(jit_type_get_size(type
) == darg
->layout
->len
);
167 if ((padding
= psi_offset_padding(darg
->layout
->pos
- offset
, alignment
))) {
168 if (nels
+ padding
> argc
) {
170 *fields
= realloc(*fields
, (argc
+ 1) * sizeof(*fields
));
172 psi_jit_struct_type_pad(&(*fields
)[nels
], padding
);
176 assert(offset
== darg
->layout
->pos
);
178 offset
= (offset
+ darg
->layout
->len
+ alignment
- 1)
180 (*fields
)[nels
++] = type
;
183 /* apply struct alignment padding */
184 offset
= (offset
+ maxalign
- 1) & ~(maxalign
- 1);
186 assert(offset
<= strct
->size
);
187 if (offset
< strct
->size
) {
188 nels
+= psi_jit_struct_type_pad(&(*fields
)[nels
], strct
->size
- offset
);
193 static inline jit_type_t
psi_jit_decl_type(struct psi_decl_type
*type
)
195 struct psi_decl_type
*real
= psi_decl_type_get_real(type
);
197 switch (real
->type
) {
199 if (!real
->real
.strct
->engine
.type
) {
201 struct psi_jit_struct_type
*type
= calloc(1, sizeof(*type
));
202 jit_type_t strct
, *fields
= NULL
;
204 count
= psi_jit_struct_type_elements(real
->real
.strct
, &type
->fields
);
205 type
->strct
= jit_type_create_struct(type
->fields
, count
, 0);
207 real
->real
.strct
->engine
.type
= type
;
208 real
->real
.strct
->engine
.dtor
= psi_jit_struct_type_dtor
;
211 return real
->real
.strct
->engine
.type
;
215 struct psi_decl_arg
*arg
;
216 psi_plist_get(real
->real
.unn
->args
, 0, &arg
);
217 return psi_jit_decl_arg_type(arg
);
221 return psi_jit_token_type(real
->type
);
224 static inline jit_type_t
psi_jit_decl_arg_type(struct psi_decl_arg
*darg
)
226 if (darg
->var
->pointer_level
) {
227 return jit_type_void_ptr
;
229 return psi_jit_decl_type(darg
->type
);
233 struct psi_jit_context
{
235 jit_type_t signature
;
238 struct psi_jit_call
{
239 struct psi_context
*context
;
242 struct psi_impl
*impl
;
243 struct psi_call_frame
*frame
;
246 struct psi_let_exp
*let_exp
;
247 struct psi_jit_call
*impl_call
;
251 jit_type_t signature
;
252 void *params
[1]; /* [type1, type2, ... ] */
255 static void psi_jit_handler(jit_type_t sig
, void *result
, void **args
, void *data
)
257 struct psi_jit_call
*call
= data
;
259 psi_context_call(call
->context
, *(zend_execute_data
**)args
[0], *(zval
**) args
[1], call
->impl
.fn
.impl
);
262 static void psi_jit_callback(jit_type_t sig
, void *result
, void **args
,
265 struct psi_jit_call
*call
= data
, *impl_call
= call
->impl
.cb
.impl_call
;
266 struct psi_call_frame_callback cbdata
;
268 cbdata
.cb
= call
->impl
.cb
.let_exp
;
269 cbdata
.argc
= jit_type_num_params(sig
);
271 cbdata
.rval
= result
;
273 psi_call_frame_do_callback(impl_call
->impl
.fn
.frame
, &cbdata
);
276 static inline struct psi_jit_call
*psi_jit_call_alloc(struct psi_context
*C
,
277 struct psi_decl
*decl
)
279 size_t i
, c
= psi_plist_count(decl
->args
);
280 struct psi_jit_call
*call
= calloc(1, sizeof(*call
) + 2 * c
* sizeof(void *));
281 struct psi_decl_arg
*arg
;
285 for (i
= 0; psi_plist_get(decl
->args
, i
, &arg
); ++i
) {
286 call
->params
[i
] = psi_jit_decl_arg_type(arg
);
288 call
->params
[c
] = NULL
;
290 call
->signature
= jit_type_create_signature(
291 psi_jit_abi(decl
->abi
->convention
),
292 psi_jit_decl_arg_type(decl
->func
),
293 (jit_type_t
*) call
->params
,
295 assert(call
->signature
);
300 static inline void *psi_jit_call_init_closure(struct psi_context
*C
,
301 struct psi_jit_call
*call
, struct psi_impl
*impl
)
303 struct psi_jit_context
*context
= C
->context
;
305 call
->impl
.fn
.impl
= impl
;
306 return call
->closure
= jit_closure_create(context
->jit
, context
->signature
,
307 &psi_jit_handler
, call
);
310 static inline void *psi_jit_call_init_callback_closure(struct psi_context
*C
,
311 struct psi_jit_call
*call
, struct psi_jit_call
*impl_call
,
312 struct psi_let_exp
*cb
)
314 struct psi_jit_context
*context
= C
->context
;
316 call
->impl
.cb
.let_exp
= cb
;
317 call
->impl
.cb
.impl_call
= impl_call
;
319 return call
->closure
= jit_closure_create(context
->jit
, call
->signature
,
320 &psi_jit_callback
, call
);
323 static inline void psi_jit_call_free(struct psi_jit_call
*call
)
325 jit_type_free(call
->signature
);
329 static inline struct psi_jit_context
*psi_jit_context_init(
330 struct psi_jit_context
*L
)
332 jit_type_t params
[] = {jit_type_void_ptr
, jit_type_void_ptr
};
335 L
= malloc(sizeof(*L
));
337 memset(L
, 0, sizeof(*L
));
339 L
->jit
= jit_context_create();
340 L
->signature
= jit_type_create_signature(jit_abi_cdecl
, jit_type_void
,
346 static inline void psi_jit_context_dtor(struct psi_jit_context
*L
)
348 jit_type_free(L
->signature
);
349 jit_context_destroy(L
->jit
);
352 static inline void psi_jit_context_free(struct psi_jit_context
**L
)
355 psi_jit_context_dtor(*L
);
361 static void psi_jit_init(struct psi_context
*C
)
363 C
->context
= psi_jit_context_init(NULL
);
366 static inline void psi_jit_destroy_callbacks(struct psi_context
*C
,
367 struct psi_let_exp
*let_exp
)
369 struct psi_let_callback
*cb
;
370 struct psi_let_func
*fn
= NULL
;
372 switch (let_exp
->kind
) {
373 case PSI_LET_CALLBACK
:
374 cb
= let_exp
->data
.callback
;
376 if (cb
->decl
&& cb
->decl
->info
) {
377 psi_jit_call_free(cb
->decl
->info
);
383 fn
= let_exp
->data
.func
;
388 struct psi_let_exp
*inner_let
;
390 while (psi_plist_get(fn
->inner
, i
++, &inner_let
)) {
391 psi_jit_destroy_callbacks(C
, inner_let
);
400 static void psi_jit_dtor(struct psi_context
*C
)
404 struct psi_decl
*decl
;
406 while (psi_plist_get(C
->decls
, i
++, &decl
)) {
408 psi_jit_call_free(decl
->info
);
414 struct psi_impl
*impl
;
416 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
418 struct psi_let_stmt
*let
;
420 while (psi_plist_get(impl
->stmts
.let
, l
++, &let
)) {
421 psi_jit_destroy_callbacks(C
, let
->exp
);
425 psi_jit_context_free((void *) &C
->context
);
428 static inline void psi_jit_compile_callbacks(struct psi_context
*C
,
429 struct psi_jit_call
*impl_call
, struct psi_let_exp
*let_exp
)
431 struct psi_jit_call
*call
;
432 struct psi_let_callback
*cb
;
433 struct psi_let_func
*fn
= NULL
;
435 switch (let_exp
->kind
) {
436 case PSI_LET_CALLBACK
:
437 cb
= let_exp
->data
.callback
;
438 if ((call
= psi_jit_call_alloc(C
, cb
->decl
))) {
439 if (!psi_jit_call_init_callback_closure(C
, call
, impl_call
, let_exp
)) {
440 psi_jit_call_free(call
);
444 cb
->decl
->sym
= call
->closure
;
450 fn
= let_exp
->data
.func
;
454 struct psi_let_exp
*inner_let
;
456 while (psi_plist_get(fn
->inner
, i
++, &inner_let
)) {
457 psi_jit_compile_callbacks(C
, impl_call
, inner_let
);
466 static zend_function_entry
*psi_jit_compile(struct psi_context
*C
)
468 size_t i
= 0, d
= 0, nf
= 0;
469 struct psi_impl
*impl
;
470 struct psi_decl
*decl
;
471 zend_function_entry
*zfe
;
472 struct psi_jit_context
*ctx
= C
->context
;
478 zfe
= calloc(psi_plist_count(C
->impls
) + 1, sizeof(*zfe
));
479 jit_context_build_start(ctx
->jit
);
481 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
482 zend_function_entry
*zf
= &zfe
[nf
];
483 struct psi_jit_call
*call
;
485 struct psi_let_stmt
*let
;
490 if (!(call
= psi_jit_call_alloc(C
, impl
->decl
))) {
493 if (!psi_jit_call_init_closure(C
, call
, impl
)) {
494 psi_jit_call_free(call
);
498 zf
->fname
= impl
->func
->name
+ (impl
->func
->name
[0] == '\\');
499 zf
->handler
= call
->closure
;
500 zf
->num_args
= psi_plist_count(impl
->func
->args
);
501 zf
->arg_info
= psi_internal_arginfo(impl
);
504 while (psi_plist_get(impl
->stmts
.let
, l
++, &let
)) {
505 psi_jit_compile_callbacks(C
, call
, let
->exp
);
509 while (psi_plist_get(C
->decls
, d
++, &decl
)) {
514 psi_jit_call_alloc(C
, decl
);
517 jit_context_build_end(ctx
->jit
);
522 static void psi_jit_call(struct psi_context
*C
, struct psi_call_frame
*frame
,
523 struct psi_decl
*decl
, void *rval
, void **args
)
525 struct psi_jit_call
*call
= decl
->info
;
526 struct psi_call_frame
*prev
= call
->impl
.fn
.frame
;
528 call
->impl
.fn
.frame
= frame
;
529 jit_apply(call
->signature
, decl
->sym
, args
, psi_plist_count(decl
->args
), rval
);
530 call
->impl
.fn
.frame
= prev
;
533 static void psi_jit_call_va(struct psi_context
*C
, struct psi_call_frame
*frame
,
534 struct psi_decl
*decl
, void *rval
, void **args
, size_t va_count
,
537 struct psi_jit_call
*info
= decl
->info
;
538 struct psi_call_frame
*prev
= info
->impl
.fn
.frame
;
539 size_t argc
= psi_plist_count(decl
->args
);
540 jit_type_t signature
;
541 jit_type_t
*param_types
= ecalloc(argc
+ va_count
+ 1, sizeof(jit_type_t
));
543 memcpy(param_types
, info
->params
, argc
* sizeof(jit_type_t
));
544 memcpy(param_types
+ argc
, va_types
, va_count
* sizeof(jit_type_t
));
546 signature
= jit_type_create_signature(jit_abi_vararg
,
547 jit_type_get_return(info
->signature
), param_types
, argc
+ va_count
,
551 info
->impl
.fn
.frame
= frame
;
552 jit_apply(signature
, decl
->sym
, args
, argc
, rval
);
553 info
->impl
.fn
.frame
= prev
;
554 jit_type_free(signature
);
558 static void *psi_jit_query(struct psi_context
*C
, enum psi_context_query q
,
562 case PSI_CONTEXT_QUERY_SELF
:
564 case PSI_CONTEXT_QUERY_TYPE
:
565 return psi_jit_impl_type(*(token_t
*) arg
);
570 static struct psi_context_ops ops
= {psi_jit_init
, psi_jit_dtor
,
571 psi_jit_compile
, psi_jit_call
, psi_jit_call_va
, psi_jit_query
};
573 struct psi_context_ops
*psi_libjit_ops(void)
578 #endif /* HAVE_LIBJIT */