flush
[m6w6/ext-psi] / src / libjit.c
1 #include "php.h"
2 #include "libjit.h"
3 #include "parser_proc.h"
4 #include "parser.h"
5
6 #include <jit/jit.h>
7
8 static void init(PSI_Context *C)
9 {
10 C->context = jit_context_create();
11 }
12
13 static void dtor(PSI_Context *C)
14 {
15 jit_context_destroy(C->context);
16 C->context = NULL;
17 }
18
19 static inline size_t impl_num_min_args(impl *impl) {
20 size_t i, n = impl->func->args->count;
21
22 for (i = 0; i < impl->func->args->count; ++i) {
23 if (impl->func->args->args[i]->def) {
24 --n;
25 }
26 }
27 return n;
28 }
29
30 static inline jit_abi_t psi_jit_abi(const char *convention) {
31 return jit_abi_cdecl;
32 }
33 static inline jit_type_t psi_jit_type(token_t t) {
34 switch (t) {
35 default:
36 ZEND_ASSERT(0);
37 /* no break */
38 case PSI_T_VOID:
39 return jit_type_void;
40 case PSI_T_SINT8:
41 return jit_type_sbyte;
42 case PSI_T_UINT8:
43 return jit_type_ubyte;
44 case PSI_T_SINT16:
45 return jit_type_short;
46 case PSI_T_UINT16:
47 return jit_type_ushort;
48 case PSI_T_SINT32:
49 return jit_type_int;
50 case PSI_T_UINT32:
51 return jit_type_uint;
52 case PSI_T_SINT64:
53 return jit_type_long;
54 case PSI_T_UINT64:
55 return jit_type_ulong;
56 case PSI_T_BOOL:
57 return jit_type_sys_bool;
58 case PSI_T_CHAR:
59 return jit_type_sys_char;
60 case PSI_T_SHORT:
61 return jit_type_sys_short;
62 case PSI_T_INT:
63 return jit_type_sys_int;
64 case PSI_T_LONG:
65 return jit_type_sys_long;
66 case PSI_T_FLOAT:
67 return jit_type_sys_float;
68 case PSI_T_DOUBLE:
69 return jit_type_sys_double;
70 }
71 }
72 static inline jit_type_t psi_jit_decl_type(decl_type *type) {
73 return psi_jit_type(real_decl_type(type)->type);
74 }
75 static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) {
76 if (darg->var->pointer_level) {
77 return jit_type_void_ptr;
78 } else {
79 return psi_jit_decl_type(darg->type);
80 }
81 }
82
83 typedef struct PSI_ClosureData {
84 void *context;
85 impl *impl;
86 jit_type_t signature;
87 jit_type_t params[1];
88 } PSI_ClosureData;
89
90 static inline PSI_ClosureData *PSI_ClosureDataAlloc(void *context, impl *impl) {
91 size_t i, c = impl->decl->args->count;
92 PSI_ClosureData *data = malloc(sizeof(*data) + (c ? c-1 : c) * sizeof(jit_type_t));
93
94 data->context = context;
95 data->impl = impl;
96 for (i = 0; i < c; ++i) {
97 data->params[i] = psi_jit_decl_arg_type(impl->decl->args->args[i]);
98 }
99 data->signature = jit_type_create_signature(
100 psi_jit_abi(data->impl->decl->abi->convention),
101 psi_jit_decl_arg_type(data->impl->decl->func),
102 data->params,
103 data->impl->decl->args->count,
104 1);
105 return data;
106 }
107
108
109 static inline impl_val *deref(unsigned level, impl_val *ret_val, decl_arg *darg) {
110 unsigned i;
111
112 for (i = level; i < darg->var->pointer_level; ++i && ret_val->ptr) {
113 ret_val = *(void **)ret_val;
114 }
115
116 return ret_val;
117 }
118 static void to_int(impl_val *ret_val, decl_arg *func, zval *return_value) {
119 switch (real_decl_type(func->type)->type) {
120 case PSI_T_FLOAT:
121 case PSI_T_DOUBLE:
122 RETVAL_DOUBLE(deref(0, ret_val, func)->dval);
123 convert_to_long(return_value);
124 break;
125 default:
126 RETVAL_LONG(deref(0, ret_val, func)->lval);
127 }
128 }
129 static void to_string(impl_val *ret_val, decl_arg *func, zval *return_value) {
130 switch (real_decl_type(func->type)->type) {
131 case PSI_T_CHAR:
132 case PSI_T_SINT8:
133 case PSI_T_UINT8:
134 if (!func->var->pointer_level) {
135 char chr = ret_val->lval;
136 RETVAL_STRINGL(&chr, 1);
137 } else {
138 ret_val = deref(1, ret_val, func);
139 if (ret_val->ptr) {
140 RETVAL_STRING(ret_val->ptr);
141 } else {
142 RETVAL_EMPTY_STRING();
143 }
144 }
145 break;
146 case PSI_T_FLOAT:
147 case PSI_T_DOUBLE:
148 RETVAL_DOUBLE(deref(0, ret_val, func)->dval);
149 convert_to_string(return_value);
150 break;
151 default:
152 RETVAL_LONG(deref(0, ret_val, func)->lval);
153 convert_to_string(return_value);
154 break;
155 }
156 }
157
158 static ZEND_RESULT_CODE handle_args(zend_execute_data *execute_data, impl *impl) {
159 impl_arg *iarg;
160
161 if (!impl->func->args->count) {
162 return zend_parse_parameters_none();
163 }
164
165 ZEND_PARSE_PARAMETERS_START(impl_num_min_args(impl), impl->func->args->count)
166 nextarg:
167 iarg = impl->func->args->args[_i];
168 if (iarg->def) {
169 Z_PARAM_OPTIONAL;
170 }
171 if (PSI_T_BOOL == iarg->type->type) {
172 if (iarg->def) {
173 iarg->val.cval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
174 }
175 Z_PARAM_BOOL(iarg->val.cval);
176 } else if (PSI_T_INT == iarg->type->type) {
177 if (iarg->def) {
178 iarg->val.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
179 }
180 Z_PARAM_LONG(iarg->val.lval);
181 } else if (PSI_T_FLOAT == iarg->type->type) {
182 if (iarg->def) {
183 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
184 }
185 Z_PARAM_DOUBLE(iarg->val.dval);
186 } else if (PSI_T_STRING == iarg->type->type) {
187 struct {char *val; size_t len;} str;
188 if (iarg->def) {
189 /* FIXME */
190 str.len = strlen(iarg->def->text) - 2;
191 str.val = &iarg->def->text[1];
192 }
193 Z_PARAM_STR_EX(iarg->val.str, 1, 0);
194 if (iarg->val.str) {
195 zend_string_addref(iarg->val.str);
196 } else if (iarg->def) {
197 iarg->val.str = zend_string_init(str.val, str.len, 0);
198 }
199 } else {
200 error_code = ZPP_ERROR_FAILURE;
201 break;
202 }
203 iarg->_zv = _arg;
204 if (_i < _max_num_args) {
205 goto nextarg;
206 }
207 ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
208
209 return SUCCESS;
210 }
211
212 static impl_val *handle_let(decl_arg *darg, impl_arg *iarg) {
213 impl_val *arg_val = &darg->let->out;
214
215 if (!iarg) {
216 /* let foo = NULL */
217 memset(arg_val, 0, sizeof(*arg_val));
218 return arg_val;
219 }
220 switch (darg->let->val->func->type) {
221 case PSI_T_BOOLVAL:
222 if (iarg->type->type == PSI_T_BOOL) {
223 arg_val->cval = iarg->val.cval;
224 } else {
225 arg_val->cval = zend_is_true(iarg->_zv);
226 }
227 break;
228 case PSI_T_INTVAL:
229 if (iarg->type->type == PSI_T_INT) {
230 arg_val->lval = iarg->val.lval;
231 } else {
232 arg_val->lval = zval_get_long(iarg->_zv);
233 }
234 break;
235 case PSI_T_STRVAL:
236 if (iarg->type->type == PSI_T_STRING) {
237 arg_val->ptr = estrdup(iarg->val.str->val);
238 darg->let->mem = arg_val->ptr;
239 zend_string_release(iarg->val.str);
240 } else {
241 zend_string *zs = zval_get_string(iarg->_zv);
242 arg_val->ptr = estrdup(zs->val);
243 darg->let->mem = arg_val->ptr;
244 zend_string_release(zs);
245 }
246 break;
247 case PSI_T_STRLEN:
248 if (iarg->type->type == PSI_T_STRING) {
249 arg_val->lval = iarg->val.str->len;
250 zend_string_release(iarg->val.str);
251 } else {
252 zend_string *zs = zval_get_string(iarg->_zv);
253 arg_val->lval = zs->len;
254 zend_string_release(zs);
255 }
256 break;
257 EMPTY_SWITCH_DEFAULT_CASE();
258 }
259
260 return arg_val;
261 }
262
263 static void handle_rval(impl *impl, impl_val *ret_val, zval *return_value) {
264 switch (impl->stmts->ret.list[0]->func->type) {
265 case PSI_T_TO_STRING:
266 to_string(ret_val, impl->decl->func, return_value);
267 break;
268 case PSI_T_TO_INT:
269 to_int(ret_val, impl->decl->func, return_value);
270 break;
271 EMPTY_SWITCH_DEFAULT_CASE();
272 }
273 }
274
275 static void handle_set(zval *return_value, set_func *func, decl_vars *vars) {
276 impl_val *val = &vars->vars[0]->arg->let->ptr;
277
278 ZVAL_DEREF(return_value);
279 zval_dtor(return_value);
280
281 switch (func->type) {
282 case PSI_T_TO_STRING:
283 to_string(val, vars->vars[0]->arg, return_value);
284 break;
285 EMPTY_SWITCH_DEFAULT_CASE();
286 }
287 }
288
289 static void handle_free(free_stmt *fre) {
290 size_t i;
291
292 for (i = 0; i < fre->vars->count; ++i) {
293 decl_var *dvar = fre->vars->vars[i];
294
295 if (dvar->arg && dvar->arg->let->out.ptr) {
296 free(dvar->arg->let->out.ptr);
297 dvar->arg->let->out.ptr = NULL;
298 }
299 }
300 }
301
302 static void handler(jit_type_t _sig, void *result, void **_args, void *_data)
303 {
304 PSI_ClosureData *data = _data;
305 size_t i;
306 void **arg_ptr = NULL, **arg_prm = NULL;
307 impl_val ret_val;
308
309 if (SUCCESS != handle_args(*(zend_execute_data **)_args[0], data->impl)) {
310 return;
311 }
312
313 if (data->impl->decl->args->count) {
314 arg_ptr = malloc(data->impl->decl->args->count * sizeof(*arg_ptr));
315 arg_prm = malloc(data->impl->decl->args->count * sizeof(*arg_prm));
316
317 for (i = 0; i < data->impl->decl->args->count; ++i) {
318 decl_arg *darg = data->impl->decl->args->args[i];
319 impl_arg *iarg = darg->let ? darg->let->arg : NULL;
320
321 arg_ptr[i] = handle_let(darg, iarg);
322 arg_prm[i] = darg->let->val->is_reference ? &arg_ptr[i] : arg_ptr[i];
323
324 darg->let->ptr = arg_ptr[i];
325 }
326 }
327
328 jit_apply(data->signature, data->impl->decl->dlptr, arg_prm, data->impl->decl->args->count, &ret_val);
329
330 handle_rval(data->impl, &ret_val, *(zval **)_args[1]);
331
332 for (i = 0; i < data->impl->stmts->set.count; ++i) {
333 set_stmt *set = data->impl->stmts->set.list[i];
334
335 handle_set(set->arg->_zv, set->val->func, set->val->vars);
336 }
337
338 if (data->impl->decl->args->count) {
339 for (i = 0; i < data->impl->decl->args->count; ++i) {
340 decl_arg *darg = data->impl->decl->args->args[i];
341
342 if (darg->let && darg->let->mem) {
343 efree(darg->let->mem);
344 darg->let->mem = NULL;
345 }
346 }
347 free(arg_ptr);
348 free(arg_prm);
349 }
350
351 for (i = 0; i < data->impl->stmts->fre.count; ++i) {
352 free_stmt *fre = data->impl->stmts->fre.list[i];
353
354 handle_free(fre);
355 }
356 }
357
358 static inline int fill_type_hint(impl_type *type) {
359 switch (type->type) {
360 case PSI_T_BOOL:
361 return _IS_BOOL;
362 case PSI_T_INT:
363 case PSI_T_LONG:
364 return IS_LONG;
365 case PSI_T_FLOAT:
366 case PSI_T_DOUBLE:
367 return IS_DOUBLE;
368 case PSI_T_STRING:
369 return IS_STRING;
370 case PSI_T_ARRAY:
371 return IS_ARRAY;
372 default:
373 return 0;
374 }
375 }
376
377 static inline zend_internal_arg_info *fill_arginfo(impl *impl) {
378 size_t i;
379 zend_internal_arg_info *aip;
380 zend_internal_function_info *fi;
381
382 aip = calloc(impl->func->args->count + 1, sizeof(*aip));
383
384 fi = (zend_internal_function_info *) &aip[0];
385 fi->required_num_args = impl_num_min_args(impl);
386 fi->return_reference = impl->func->return_reference;
387 fi->type_hint = fill_type_hint(impl->func->return_type);
388
389 for (i = 0; i < impl->func->args->count; ++i) {
390 impl_arg *iarg = impl->func->args->args[i];
391 zend_internal_arg_info *ai = &aip[i+1];
392
393 ai->name = iarg->var->name;
394 ai->type_hint = fill_type_hint(iarg->type);
395 if (iarg->var->reference) {
396 ai->pass_by_reference = 1;
397 }
398 if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
399 ai->allow_null = 1;
400 }
401 }
402
403 return aip;
404 }
405
406 static zend_function_entry *compile(PSI_Context *C, PSI_Data *D)
407 {
408 size_t i, j = 0;
409 jit_type_t signature, params[] = {
410 jit_type_void_ptr,
411 jit_type_void_ptr
412 };
413 zend_function_entry *zfe = calloc(D->impls->count + 1, sizeof(*zfe));
414
415 jit_context_build_start(C->context);
416
417 for (i = 0; i < D->impls->count; ++i) {
418 zend_function_entry *zf = &zfe[j];
419 PSI_ClosureData *data;
420
421 if (!D->impls->list[i]->decl) {
422 continue;
423 }
424
425 data = PSI_ClosureDataAlloc(C, D->impls->list[i]);
426 signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void, params, 2, 1);
427 zf->fname = D->impls->list[i]->func->name + (D->impls->list[i]->func->name[0] == '\\');
428 zf->handler = jit_closure_create(C->context, signature, &handler, data);
429 zf->num_args = D->impls->list[i]->func->args->count;
430 zf->arg_info = fill_arginfo(D->impls->list[i]);
431 ++j;
432 }
433
434 jit_context_build_end(C->context);
435
436 return zfe;
437 }
438
439 static PSI_ContextOps ops = {
440 init,
441 dtor,
442 compile,
443 };
444
445 PSI_ContextOps *PSI_Libjit(void)
446 {
447 return &ops;
448 }