made the real decl_type a union
[m6w6/ext-psi] / src / libjit.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include "php.h"
6
7 #ifdef HAVE_LIBJIT
8
9 #include "php_psi.h"
10 #include "libjit.h"
11 #include "engine.h"
12
13 #include <jit/jit.h>
14
15 static void psi_jit_handler(jit_type_t _sig, void *_result, void **_args, void *_data)
16 {
17 psi_call(*(zend_execute_data **)_args[0], *(zval **)_args[1], _data);
18 }
19
20 static void psi_jit_callback(jit_type_t _sig, void *_result, void **_args, void *_data)
21 {
22 psi_callback(_data, _result, jit_type_num_params(_sig), _args);
23 }
24
25 static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg);
26
27 static inline jit_abi_t psi_jit_abi(const char *convention) {
28 return jit_abi_cdecl;
29 }
30 static inline jit_type_t psi_jit_token_type(token_t t) {
31 switch (t) {
32 default:
33 ZEND_ASSERT(0);
34 /* no break */
35 case PSI_T_VOID:
36 return jit_type_void;
37 case PSI_T_INT8:
38 return jit_type_sbyte;
39 case PSI_T_UINT8:
40 return jit_type_ubyte;
41 case PSI_T_INT16:
42 return jit_type_short;
43 case PSI_T_UINT16:
44 return jit_type_ushort;
45 case PSI_T_INT32:
46 return jit_type_int;
47 case PSI_T_UINT32:
48 return jit_type_uint;
49 case PSI_T_INT64:
50 return jit_type_long;
51 case PSI_T_UINT64:
52 return jit_type_ulong;
53 case PSI_T_BOOL:
54 return jit_type_sys_bool;
55 case PSI_T_INT:
56 case PSI_T_ENUM:
57 return jit_type_sys_int;
58 case PSI_T_LONG:
59 return jit_type_sys_long;
60 case PSI_T_FLOAT:
61 return jit_type_sys_float;
62 case PSI_T_DOUBLE:
63 return jit_type_sys_double;
64 #ifdef HAVE_LONG_DOUBLE
65 case PSI_T_LONG_DOUBLE:
66 return jit_type_sys_long_double;
67 #endif
68 case PSI_T_POINTER:
69 case PSI_T_FUNCTION:
70 return jit_type_void_ptr;
71 }
72 }
73 static inline jit_type_t psi_jit_impl_type(token_t impl_type) {
74 switch (impl_type) {
75 case PSI_T_BOOL:
76 return jit_type_sbyte;
77 case PSI_T_INT:
78 return jit_type_long;
79 case PSI_T_STRING:
80 return jit_type_void_ptr;
81 case PSI_T_FLOAT:
82 case PSI_T_DOUBLE:
83 return jit_type_sys_double;
84 EMPTY_SWITCH_DEFAULT_CASE();
85 }
86 return NULL;
87 }
88
89 static void psi_jit_struct_type_dtor(void *type) {
90 jit_type_t strct = type;
91
92 jit_type_free(strct);
93 }
94
95 static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding) {
96 size_t i;
97
98 for (i = 0; i < padding; ++i) {
99 *els++ = jit_type_copy(jit_type_sys_char);
100 }
101
102 return padding;
103 }
104
105 static unsigned psi_jit_struct_type_elements(decl_struct *strct, jit_type_t **fields) {
106 size_t i, argc = strct->args->count, nels = 0, offset = 0, maxalign;
107 *fields = calloc(argc + 1, sizeof(*fields));
108
109 for (i = 0; i < strct->args->count; ++i) {
110 decl_arg *darg = strct->args->args[i];
111 jit_type_t type = jit_type_copy(psi_jit_decl_arg_type(darg));
112 size_t padding, alignment;
113
114 ZEND_ASSERT(jit_type_get_size(type) == darg->layout->len);
115
116 if ((alignment = jit_type_get_alignment(type)) > maxalign) {
117 maxalign = alignment;
118 }
119
120 if ((padding = psi_offset_padding(darg->layout->pos - offset, alignment))) {
121 if (nels + padding > argc) {
122 argc += padding;
123 *fields = realloc(*fields, (argc + 1) * sizeof(*fields));
124 }
125 psi_jit_struct_type_pad(&(*fields)[nels], padding);
126 nels += padding;
127 offset += padding;
128 }
129 ZEND_ASSERT(offset == darg->layout->pos);
130
131 offset = (offset + darg->layout->len + alignment - 1) & ~(alignment - 1);
132 (*fields)[nels++] = type;
133 }
134
135 /* apply struct alignment padding */
136 offset = (offset + maxalign - 1) & ~(maxalign - 1);
137
138 ZEND_ASSERT(offset <= strct->size);
139 if (offset < strct->size) {
140 nels += psi_jit_struct_type_pad(&(*fields)[nels], strct->size - offset);
141 }
142
143 return nels;
144 }
145 static inline jit_type_t psi_jit_decl_type(decl_type *type) {
146 decl_type *real = real_decl_type(type);
147
148 switch (real->type) {
149 case PSI_T_STRUCT:
150 if (!real->real.strct->engine.type) {
151 unsigned count;
152 jit_type_t strct, *fields = NULL;
153
154 count = psi_jit_struct_type_elements(real->real.strct, &fields);
155 strct = jit_type_create_struct(fields, count, 0);
156
157 real->real.strct->engine.type = strct;
158 real->real.strct->engine.dtor = psi_jit_struct_type_dtor;
159 }
160
161 return real->real.strct->engine.type;
162
163 case PSI_T_UNION:
164 return psi_jit_decl_arg_type(real->real.unn->args->args[0]);
165
166 default:
167 return psi_jit_token_type(real->type);
168 }
169 }
170 static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) {
171 if (darg->var->pointer_level) {
172 return jit_type_void_ptr;
173 } else {
174 return psi_jit_decl_type(darg->type);
175 }
176 }
177
178 typedef struct PSI_LibjitContext {
179 jit_context_t jit;
180 jit_type_t signature;
181 struct {
182 struct PSI_LibjitData **list;
183 size_t count;
184 } data;
185 } PSI_LibjitContext;
186
187 typedef struct PSI_LibjitCall {
188 void *closure;
189 jit_type_t signature;
190 void *params[1]; /* [type1, type2, NULL, arg1, arg2] ... */
191 } PSI_LibjitCall;
192
193 typedef struct PSI_LibjitData {
194 PSI_LibjitContext *context;
195 impl *impl;
196 zend_internal_arg_info *arginfo;
197 } PSI_LibjitData;
198
199 static inline PSI_LibjitCall *PSI_LibjitCallAlloc(PSI_Context *C, decl *decl) {
200 size_t i, c = decl->args ? decl->args->count : 0;
201 PSI_LibjitCall *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *));
202
203 for (i = 0; i < c; ++i) {
204 call->params[i] = psi_jit_decl_arg_type(decl->args->args[i]);
205 }
206 call->params[c] = NULL;
207
208 decl->call.info = call;
209 decl->call.rval = &decl->func->ptr;
210 decl->call.argc = c;
211 decl->call.args = (void **) &call->params[c+1];
212
213 call->signature = jit_type_create_signature(
214 psi_jit_abi(decl->abi->convention),
215 psi_jit_decl_arg_type(decl->func),
216 (jit_type_t *) call->params, c, 1);
217 ZEND_ASSERT(call->signature);
218
219 return call;
220 }
221
222 static inline void *PSI_LibjitCallInitClosure(PSI_Context *C, PSI_LibjitCall *call, impl *impl) {
223 PSI_LibjitContext *context = C->context;
224 return call->closure = jit_closure_create(context->jit, context->signature,
225 &psi_jit_handler, impl);
226 }
227
228 static inline void *PSI_LibjitCallInitCallbackClosure(PSI_Context *C, PSI_LibjitCall *call, let_callback *cb) {
229 PSI_LibjitContext *context = C->context;
230 return call->closure = jit_closure_create(context->jit, call->signature,
231 &psi_jit_callback, cb);
232 }
233
234 static inline void PSI_LibjitCallFree(PSI_LibjitCall *call) {
235 jit_type_free(call->signature);
236 free(call);
237 }
238
239 static inline PSI_LibjitContext *PSI_LibjitContextInit(PSI_LibjitContext *L) {
240 jit_type_t params[] = {
241 jit_type_void_ptr,
242 jit_type_void_ptr
243 };
244
245 if (!L) {
246 L = malloc(sizeof(*L));
247 }
248 memset(L, 0, sizeof(*L));
249
250 L->jit = jit_context_create();
251 L->signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void,
252 params, 2, 1);
253
254 return L;
255 }
256
257 static inline void PSI_LibjitContextDtor(PSI_LibjitContext *L) {
258 jit_type_free(L->signature);
259 jit_context_destroy(L->jit);
260 }
261
262 static inline void PSI_LibjitContextFree(PSI_LibjitContext **L) {
263 if (*L) {
264 PSI_LibjitContextDtor(*L);
265 free(*L);
266 *L = NULL;
267 }
268 }
269
270 static void psi_jit_init(PSI_Context *C)
271 {
272 C->context = PSI_LibjitContextInit(NULL);
273 }
274
275 static void psi_jit_dtor(PSI_Context *C)
276 {
277 if (C->decls) {
278 size_t i;
279
280 for (i = 0; i < C->decls->count; ++i) {
281 decl *decl = C->decls->list[i];
282
283 if (decl->call.info) {
284 PSI_LibjitCallFree(decl->call.info);
285 }
286 }
287 }
288 if (C->impls) {
289 size_t i, j;
290
291 for (i = 0; i < C->impls->count; ++i) {
292 impl *impl = C->impls->list[i];
293
294 for (j = 0; j < impl->stmts->let.count; ++j) {
295 let_stmt *let = impl->stmts->let.list[j];
296
297 if (let->val && let->val->kind == PSI_LET_CALLBACK) {
298 let_callback *cb = let->val->data.callback;
299
300 if (cb->decl && cb->decl->call.info) {
301 PSI_LibjitCallFree(cb->decl->call.info);
302 }
303 }
304 }
305 }
306 }
307 PSI_LibjitContextFree((void *) &C->context);
308 }
309
310 static zend_function_entry *psi_jit_compile(PSI_Context *C)
311 {
312 size_t c, i, j = 0;
313 zend_function_entry *zfe;
314 PSI_LibjitContext *ctx = C->context;
315
316 if (!C->impls) {
317 return NULL;
318 }
319
320 zfe = calloc(C->impls->count + 1, sizeof(*zfe));
321 jit_context_build_start(ctx->jit);
322
323 for (i = 0; i < C->impls->count; ++i) {
324 zend_function_entry *zf = &zfe[j];
325 PSI_LibjitCall *call;
326 impl *impl = C->impls->list[i];
327
328 if (!impl->decl) {
329 continue;
330 }
331
332 if ((call = PSI_LibjitCallAlloc(C, impl->decl))) {
333 if (!PSI_LibjitCallInitClosure(C, call, impl)) {
334 PSI_LibjitCallFree(call);
335 continue;
336 }
337 }
338
339 zf->fname = impl->func->name + (impl->func->name[0] == '\\');
340 zf->num_args = impl->func->args->count;
341 zf->handler = call->closure;
342 zf->arg_info = psi_internal_arginfo(impl);
343 ++j;
344
345 for (c = 0; c < impl->stmts->let.count; ++c) {
346 let_stmt *let = impl->stmts->let.list[c];
347
348 if (let->val && let->val->kind == PSI_LET_CALLBACK) {
349 let_callback *cb = let->val->data.callback;
350
351 if ((call = PSI_LibjitCallAlloc(C, cb->decl))) {
352 if (!PSI_LibjitCallInitCallbackClosure(C, call, cb)) {
353 PSI_LibjitCallFree(call);
354 continue;
355 }
356
357 cb->decl->call.sym = call->closure;
358 }
359 }
360 }
361 }
362
363 for (i = 0; i < C->decls->count; ++i) {
364 decl *decl = C->decls->list[i];
365
366 if (decl->call.info) {
367 continue;
368 }
369
370 PSI_LibjitCallAlloc(C, decl);
371 }
372
373 jit_context_build_end(ctx->jit);
374
375 return zfe;
376 }
377
378 static void psi_jit_call(PSI_Context *C, decl_callinfo *decl_call, impl_vararg *va) {
379 PSI_LibjitCall *call = decl_call->info;
380
381 if (va) {
382 jit_type_t signature;
383 size_t i, nfixedargs = decl_call->argc, ntotalargs = nfixedargs + va->args->count;
384 void **params = calloc(2 * ntotalargs + 2, sizeof(void *));
385
386 for (i = 0; i < nfixedargs; ++i) {
387 params[i] = call->params[i];
388 params[i + ntotalargs + 1] = call->params[i + nfixedargs + 1];
389 }
390 for (i = 0; i < va->args->count; ++i) {
391 params[nfixedargs + i] = psi_jit_impl_type(va->types[i]);
392 params[nfixedargs + i + ntotalargs + 1] = &va->values[i];
393 }
394
395 signature = jit_type_create_signature(
396 jit_type_get_abi(call->signature),
397 jit_type_get_return(call->signature),
398 (jit_type_t *) params, ntotalargs, 1);
399 ZEND_ASSERT(signature);
400
401 jit_apply(signature, decl_call->sym, &params[ntotalargs + 1],
402 nfixedargs, *decl_call->rval);
403 jit_type_free(signature);
404 free(params);
405 } else {
406 jit_apply(call->signature, decl_call->sym, decl_call->args,
407 decl_call->argc, *decl_call->rval);
408 }
409 }
410
411 static PSI_ContextOps ops = {
412 psi_jit_init,
413 psi_jit_dtor,
414 psi_jit_compile,
415 psi_jit_call,
416 };
417
418 PSI_ContextOps *PSI_Libjit(void)
419 {
420 return &ops;
421 }
422
423 #endif /* HAVE_LIBJIT */