libjit vararg call
[m6w6/ext-psi] / src / module.c
1
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5
6 #include "php.h"
7 #include "php_ini.h"
8 #include "ext/standard/info.h"
9 #include "zend_exceptions.h"
10 #include "zend_constants.h"
11 #include "zend_operators.h"
12
13 #include "php_psi.h"
14
15 #if HAVE_LIBJIT
16 # include "libjit.h"
17 # ifndef HAVE_LIBFFI
18 # define PSI_ENGINE "jit"
19 # endif
20 #endif
21 #if HAVE_LIBFFI
22 # include "libffi.h"
23 # define PSI_ENGINE "ffi"
24 #endif
25
26 ZEND_DECLARE_MODULE_GLOBALS(psi);
27
28 PHP_INI_BEGIN()
29 STD_PHP_INI_ENTRY("psi.engine", PSI_ENGINE, PHP_INI_SYSTEM, OnUpdateString, engine, zend_psi_globals, psi_globals)
30 STD_PHP_INI_ENTRY("psi.directory", "psi.d", PHP_INI_SYSTEM, OnUpdateString, directory, zend_psi_globals, psi_globals)
31 PHP_INI_END();
32
33 static zend_object_handlers psi_object_handlers;
34 static zend_class_entry *psi_class_entry;
35
36 void psi_error(int type, const char *msg, ...)
37 {
38 char buf[0x1000];
39 va_list argv;
40
41 va_start(argv, msg);
42 vslprintf(buf, 0x1000, msg, argv);
43 va_end(argv);
44
45 php_error(type, buf);
46 }
47
48 size_t psi_t_alignment(token_t t)
49 {
50 #define PSI_ALIGNOF(T) case PSI_T_## T: return ALIGNOF_## T ##_T;
51 switch (t) {
52 PSI_ALIGNOF(INT8);
53 PSI_ALIGNOF(UINT8);
54 PSI_ALIGNOF(INT16);
55 PSI_ALIGNOF(UINT16);
56 PSI_ALIGNOF(INT32);
57 PSI_ALIGNOF(UINT32);
58 PSI_ALIGNOF(INT64);
59 PSI_ALIGNOF(UINT64);
60 case PSI_T_FLOAT:
61 return ALIGNOF_FLOAT;
62 case PSI_T_DOUBLE:
63 return ALIGNOF_DOUBLE;
64 case PSI_T_POINTER:
65 return ALIGNOF_VOID_P;
66 EMPTY_SWITCH_DEFAULT_CASE();
67 }
68 return 0;
69 }
70
71 size_t psi_t_size(token_t t)
72 {
73 #define PSI_SIZEOF(T) case PSI_T_## T : return SIZEOF_## T ##_T;
74 switch (t) {
75 PSI_SIZEOF(INT8);
76 PSI_SIZEOF(UINT8);
77 PSI_SIZEOF(INT16);
78 PSI_SIZEOF(UINT16);
79 PSI_SIZEOF(INT32);
80 PSI_SIZEOF(UINT32);
81 PSI_SIZEOF(INT64);
82 PSI_SIZEOF(UINT64);
83 case PSI_T_FLOAT:
84 return SIZEOF_FLOAT;
85 case PSI_T_DOUBLE:
86 return SIZEOF_DOUBLE;
87 case PSI_T_POINTER:
88 return SIZEOF_VOID_P;
89 EMPTY_SWITCH_DEFAULT_CASE();
90 }
91 return 0;
92 }
93
94 size_t psi_t_align(token_t t, size_t s)
95 {
96 size_t a = psi_t_alignment(t);
97 return ((s - 1) | (a - 1)) + 1;
98 }
99
100 int psi_internal_type(impl_type *type)
101 {
102 switch (type->type) {
103 case PSI_T_BOOL:
104 return _IS_BOOL;
105 case PSI_T_INT:
106 return IS_LONG;
107 case PSI_T_FLOAT:
108 case PSI_T_DOUBLE:
109 return IS_DOUBLE;
110 case PSI_T_STRING:
111 return IS_STRING;
112 case PSI_T_ARRAY:
113 return IS_ARRAY;
114 default:
115 return 0;
116 }
117 }
118
119 zend_internal_arg_info *psi_internal_arginfo(impl *impl)
120 {
121 size_t i;
122 zend_internal_arg_info *aip;
123 zend_internal_function_info *fi;
124
125 aip = calloc(impl->func->args->count + 1 + !!impl->func->args->vararg.name, sizeof(*aip));
126
127 fi = (zend_internal_function_info *) &aip[0];
128 fi->allow_null = 1;
129 fi->required_num_args = psi_num_min_args(impl);
130 fi->return_reference = impl->func->return_reference;
131 fi->type_hint = psi_internal_type(impl->func->return_type);
132
133 if (impl->func->args->vararg.name) {
134 impl_arg *vararg = impl->func->args->vararg.name;
135 zend_internal_arg_info *ai = &aip[impl->func->args->count];
136
137 ai->name = vararg->var->name;
138 ai->type_hint = psi_internal_type(vararg->type);
139 if (vararg->var->reference) {
140 ai->pass_by_reference = 1;
141 }
142 ai->is_variadic = 1;
143 }
144
145 for (i = 0; i < impl->func->args->count; ++i) {
146 impl_arg *iarg = impl->func->args->args[i];
147 zend_internal_arg_info *ai = &aip[i+1];
148
149 ai->name = iarg->var->name;
150 ai->type_hint = psi_internal_type(iarg->type);
151 if (iarg->var->reference) {
152 ai->pass_by_reference = 1;
153 }
154 if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
155 ai->allow_null = 1;
156 }
157 }
158
159 return aip;
160 }
161
162 size_t psi_num_min_args(impl *impl)
163 {
164 size_t i, n = impl->func->args->count;
165
166 for (i = 0; i < impl->func->args->count; ++i) {
167 if (impl->func->args->args[i]->def) {
168 --n;
169 }
170 }
171 return n;
172 }
173
174 void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val)
175 {
176 RETVAL_NULL();
177 }
178
179 void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val)
180 {
181 psi_to_int(return_value, set, ret_val);
182 convert_to_boolean(return_value);
183 }
184
185 void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val)
186 {
187 decl_var *var = set->vars->vars[0];
188 token_t t = real_decl_type(var->arg->type)->type;
189 impl_val *v = deref_impl_val(ret_val, var);
190
191 switch (t) {
192 case PSI_T_FLOAT:
193 RETVAL_DOUBLE((double) v->fval);
194 convert_to_long(return_value);
195 break;
196 case PSI_T_DOUBLE:
197 RETVAL_DOUBLE(v->dval);
198 convert_to_long(return_value);
199 break;
200 case PSI_T_INT8:
201 RETVAL_LONG(v->i8);
202 break;
203 case PSI_T_UINT8:
204 RETVAL_LONG(v->u8);
205 break;
206 case PSI_T_INT16:
207 RETVAL_LONG(v->i16);
208 break;
209 case PSI_T_UINT16:
210 RETVAL_LONG(v->u16);
211 break;
212 case PSI_T_INT32:
213 RETVAL_LONG(v->i32);
214 break;
215 case PSI_T_UINT32:
216 #if UINT32_MAX >= ZEND_LONG_MAX
217 if (v->u32 > ZEND_LONG_MAX) {
218 char d[12] = {0};
219
220 RETVAL_STRING(zend_print_ulong_to_buf(&d[10], v->u32));
221 } else {
222 #endif
223 RETVAL_LONG(v->u32);
224 #if UINT32_MAX >= ZEND_LONG_MAX
225 }
226 #endif
227 break;
228 case PSI_T_INT64:
229 RETVAL_LONG(v->i64);
230 break;
231 case PSI_T_UINT64:
232 if (v->u64 > ZEND_LONG_MAX) {
233 char d[24] = {0};
234
235 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], v->u64));
236 } else {
237 RETVAL_LONG(v->u64);
238 }
239 break;
240 EMPTY_SWITCH_DEFAULT_CASE();
241 }
242 }
243
244 void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val)
245 {
246 decl_var *var = set->vars->vars[0];
247 token_t t = real_decl_type(var->arg->type)->type;
248 impl_val *v = deref_impl_val(ret_val, var);
249
250 switch (t) {
251 case PSI_T_FLOAT:
252 RETVAL_DOUBLE((double) v->fval);
253 break;
254 case PSI_T_DOUBLE:
255 RETVAL_DOUBLE(v->dval);
256 break;
257 case PSI_T_INT8:
258 RETVAL_DOUBLE((double) v->i8);
259 break;
260 case PSI_T_UINT8:
261 RETVAL_DOUBLE((double) v->u8);
262 break;
263 case PSI_T_INT16:
264 RETVAL_DOUBLE((double) v->i16);
265 break;
266 case PSI_T_UINT16:
267 RETVAL_DOUBLE((double) v->u16);
268 break;
269 case PSI_T_INT32:
270 RETVAL_DOUBLE((double) v->i32);
271 break;
272 case PSI_T_UINT32:
273 RETVAL_DOUBLE((double) v->u32);
274 break;
275 case PSI_T_INT64:
276 RETVAL_DOUBLE((double) v->i64);
277 break;
278 case PSI_T_UINT64:
279 RETVAL_DOUBLE((double) v->u64);
280 break;
281 EMPTY_SWITCH_DEFAULT_CASE();
282 }
283 }
284
285 void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val)
286 {
287 decl_var *var = set->vars->vars[0];
288 token_t t = real_decl_type(var->arg->type)->type;
289
290 switch (t) {
291 case PSI_T_VOID:
292 case PSI_T_INT8:
293 case PSI_T_UINT8:
294 if (!var->arg->var->pointer_level) {
295 RETVAL_STRINGL(&ret_val->cval, 1);
296 } else {
297 ret_val = deref_impl_val(ret_val, var);
298 if (ret_val && ret_val->ptr) {
299 if (set->num) {
300 RETVAL_STRINGL(ret_val->ptr, psi_long_num_exp(set->num, set->outer.val));
301 } else {
302 RETVAL_STRING(ret_val->ptr);
303 }
304 } else {
305 RETVAL_EMPTY_STRING();
306 }
307 }
308 return;
309 case PSI_T_FLOAT:
310 RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval);
311 break;
312 case PSI_T_DOUBLE:
313 RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval);
314 break;
315 default:
316 psi_to_int(return_value, set, ret_val);
317 break;
318 }
319 convert_to_string(return_value);
320 }
321
322
323 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
324 {
325 memset(tmp, 0, sizeof(*tmp));
326 memcpy(tmp, ((void*) val->ptr) + size * i, size);
327 return tmp;
328 }
329
330 void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
331 {
332 decl_type *type = real_decl_type(spec->type);
333
334 switch (type->type) {
335 case PSI_T_FLOAT:
336 mem->fval = (float) zval_get_double(zv);
337 break;
338 case PSI_T_DOUBLE:
339 mem->dval = zval_get_double(zv);
340 break;
341 case PSI_T_INT8:
342 case PSI_T_UINT8:
343 if (spec->var->pointer_level) {
344 zend_string *zs = zval_get_string(zv);
345 *tmp = mem->ptr = estrndup(zs->val, zs->len);
346 zend_string_release(zs);
347 break;
348 }
349 /* no break */
350 default:
351 mem->zend.lval = zval_get_long(zv);
352 break;
353 }
354 }
355
356 void *psi_array_to_struct(decl_struct *s, HashTable *arr)
357 {
358 size_t i, j = 0;
359 char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *));
360
361 if (arr) for (i = 0; i < s->args->count; ++i) {
362 decl_arg *darg = s->args->args[i];
363 zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
364
365 if (entry) {
366 impl_val val;
367 void *tmp = NULL;
368
369 memset(&tmp, 0, sizeof(tmp));
370 psi_from_zval(&val, darg, entry, &tmp);
371 memcpy(mem + darg->layout->pos, &val, darg->layout->len);
372 if (tmp) {
373 ((void **)(mem + s->size))[j++] = tmp;
374 }
375 }
376 }
377 return mem;
378 }
379
380 void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
381 {
382 size_t i;
383 decl_var *var = set->vars->vars[0];
384 token_t t = real_decl_type(var->arg->type)->type;
385 impl_val tmp, *ret_val = deref_impl_val(r_val, var);
386
387 if ((intptr_t) ret_val->ptr <= (intptr_t) 0) {
388 RETURN_NULL();
389 }
390
391 array_init(return_value);
392
393 if (t == PSI_T_STRUCT) {
394 // decl_struct *s = real_decl_type(var->arg->type)->strct;
395
396 if (set->count) {
397 /* explicit member casts */
398 for (i = 0; i < set->count; ++i) {
399 set_value *sub_set = set->inner[i];
400 decl_var *sub_var = sub_set->vars->vars[0];
401
402 sub_set->outer.val = r_val;
403
404 if (sub_var->arg) {
405 impl_val *tmp = NULL, *val;
406 zval ztmp;
407
408 val = deref_impl_val(struct_member_ref(sub_var->arg, ret_val, &tmp), sub_var);
409 sub_set->func->handler(&ztmp, sub_set, val);
410 add_assoc_zval(return_value, sub_var->name, &ztmp);
411
412 if (tmp) {
413 free(tmp);
414 }
415 }
416 }
417 }
418 return;
419 }
420
421 if (var->arg->var->array_size) {
422 /* to_array(foo[NUMBER]) */
423 for (i = 0; i < var->arg->var->array_size; ++i) {
424 size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t);
425 impl_val *ptr = iterate(ret_val, size, i, &tmp);
426 zval ele;
427
428 switch (t) {
429 case PSI_T_FLOAT:
430 ZVAL_DOUBLE(&ele, (double) ptr->fval);
431 break;
432 case PSI_T_DOUBLE:
433 ZVAL_DOUBLE(&ele, ptr->dval);
434 break;
435 default:
436 ZVAL_LONG(&ele, ptr->lval);
437 break;
438 }
439
440 add_next_index_zval(return_value, &ele);
441 }
442 return;
443 } else if (set->num) {
444 /* to_array(arr_var, num_expr, to_int(*arr_var))
445 */
446 zval ele;
447 zend_long i, n = psi_long_num_exp(set->num, set->outer.val);
448
449 for (i = 0; i < n; ++i) {
450 size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
451 impl_val *ptr = iterate(ret_val, size, i, &tmp);
452
453 set->inner[0]->func->handler(&ele, set->inner[0], ptr);
454 add_next_index_zval(return_value, &ele);
455 }
456 } else {
457 ZEND_ASSERT(0);
458 }
459 }
460
461 void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
462 {
463 decl_var *var = set->vars->vars[0];
464 impl_val *ret_val = deref_impl_val(r_val, var);
465 psi_object *obj;
466
467 if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
468 object_init_ex(return_value, psi_class_entry);
469 obj = PSI_OBJ(return_value, NULL);
470 obj->data = ret_val->ptr;
471 } else {
472 RETVAL_NULL();
473 }
474 }
475
476 static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
477 {
478 size_t i;
479 impl_arg *iarg;
480 zend_error_handling zeh;
481
482 zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh);
483
484 if (!impl->func->args->count) {
485 ZEND_RESULT_CODE rv;
486
487 rv = zend_parse_parameters_none();
488 zend_restore_error_handling(&zeh);
489 return rv;
490 }
491
492 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->vararg.name ? -1 : impl->func->args->count)
493 nextarg:
494 if (impl->func->args->vararg.name && _i >= impl->func->args->count) {
495 impl_arg *varg = impl->func->args->vararg.name;
496 iarg = init_impl_arg(
497 init_impl_type(varg->type->type, varg->type->name),
498 init_impl_var(varg->var->name, varg->var->reference),
499 NULL);
500
501 Z_PARAM_OPTIONAL;
502 if (_i == impl->func->args->count) {
503 impl->func->args->vararg.args = init_impl_args(iarg);
504 } else {
505 add_impl_arg(impl->func->args->vararg.args, iarg);
506 }
507 } else {
508 iarg = impl->func->args->args[_i];
509 if (iarg->def) {
510 Z_PARAM_OPTIONAL;
511 }
512 }
513 if (PSI_T_BOOL == iarg->type->type) {
514 Z_PARAM_BOOL(iarg->val.zend.bval);
515 } else if (PSI_T_INT == iarg->type->type) {
516 Z_PARAM_LONG(iarg->val.zend.lval);
517 } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
518 Z_PARAM_DOUBLE(iarg->val.dval);
519 } else if (PSI_T_STRING == iarg->type->type) {
520 Z_PARAM_STR_EX(iarg->val.zend.str, 1, iarg->var->reference);
521 if (iarg->val.zend.str) {
522 zend_string_addref(iarg->val.zend.str);
523 }
524 } else if (PSI_T_ARRAY == iarg->type->type) {
525 Z_PARAM_PROLOGUE(0);
526 } else if (PSI_T_OBJECT == iarg->type->type) {
527 Z_PARAM_PROLOGUE(0);
528 } else if (PSI_T_MIXED == iarg->type->type) {
529 Z_PARAM_PROLOGUE(0);
530 } else {
531 error_code = ZPP_ERROR_FAILURE;
532 break;
533 }
534 iarg->_zv = _arg;
535 ZVAL_DEREF(iarg->_zv);
536 if (_i < _num_args) {
537 goto nextarg;
538 }
539 ZEND_PARSE_PARAMETERS_END_EX(
540 zend_restore_error_handling(&zeh);
541 return FAILURE
542 );
543
544 /* set up defaults */
545 for (i = 0; i < impl->func->args->count; ++i) {
546 if (i >= EX_NUM_ARGS() && iarg->def) {
547 iarg = impl->func->args->args[i];
548
549 switch (iarg->type->type) {
550 case PSI_T_BOOL:
551 iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
552 break;
553 case PSI_T_INT:
554 iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
555 break;
556 case PSI_T_FLOAT:
557 case PSI_T_DOUBLE:
558 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
559 break;
560 case PSI_T_STRING:
561 /* FIXME */
562 iarg->val.zend.str = zend_string_init(&iarg->def->text[1], strlen(iarg->def->text) - 2, 0);
563 break;
564 }
565 }
566 }
567
568 zend_restore_error_handling(&zeh);
569 return SUCCESS;
570 }
571
572 static inline void *psi_do_calloc(let_calloc *alloc)
573 {
574 zend_long n = psi_long_num_exp(alloc->nmemb, NULL), s = psi_long_num_exp(alloc->size, NULL);
575 void *mem = safe_emalloc(n, s, sizeof(void *));
576 memset(mem, 0, n * s + sizeof(void *));
577 return mem;
578 }
579
580 static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, impl_val *arg_val, decl_struct *strct, void **to_free)
581 {
582 switch (let_func) {
583 case PSI_T_BOOLVAL:
584 if (iarg->type->type == PSI_T_BOOL) {
585 arg_val->cval = iarg->val.zend.bval;
586 } else {
587 arg_val->cval = zend_is_true(iarg->_zv);
588 }
589 break;
590 case PSI_T_INTVAL:
591 if (iarg->type->type == PSI_T_INT) {
592 arg_val->lval = iarg->val.zend.lval;
593 } else {
594 arg_val->lval = zval_get_long(iarg->_zv);
595 }
596 break;
597 case PSI_T_FLOATVAL:
598 if (iarg->type->type == PSI_T_FLOAT || iarg->type->type == PSI_T_DOUBLE) {
599 arg_val->dval = iarg->val.dval;
600 } else {
601 arg_val->dval = zval_get_double(iarg->_zv);
602 }
603 break;
604 case PSI_T_PATHVAL:
605 case PSI_T_STRVAL:
606 if (iarg->type->type == PSI_T_STRING) {
607 if (iarg->val.zend.str) {
608 arg_val->ptr = estrdup(iarg->val.zend.str->val);
609 *to_free = arg_val->ptr;
610 } else {
611 arg_val->ptr = "";
612 }
613 } else {
614 zend_string *zs = zval_get_string(iarg->_zv);
615 arg_val->ptr = estrdup(zs->val);
616 *to_free = arg_val->ptr;
617 zend_string_release(zs);
618 }
619 if (PSI_T_PATHVAL == let_func) {
620 if (SUCCESS != php_check_open_basedir(arg_val->ptr)) {
621 efree(arg_val->ptr);
622 return FAILURE;
623 }
624 }
625 break;
626 case PSI_T_STRLEN:
627 if (iarg->type->type == PSI_T_STRING) {
628 if (iarg->val.zend.str) {
629 arg_val->lval = iarg->val.zend.str->len;
630 } else {
631 arg_val->lval = 0;
632 }
633 } else {
634 zend_string *zs = zval_get_string(iarg->_zv);
635 arg_val->lval = zs->len;
636 zend_string_release(zs);
637 }
638 break;
639 case PSI_T_ARRVAL:
640 if (iarg->type->type == PSI_T_ARRAY) {
641 arg_val->ptr = psi_array_to_struct(strct, HASH_OF(iarg->_zv));
642 *to_free = arg_val->ptr;
643 }
644 break;
645 case PSI_T_OBJVAL:
646 if (iarg->type->type == PSI_T_OBJECT) {
647 psi_object *obj;
648
649 if (!instanceof_function(Z_OBJCE_P(iarg->_zv), psi_class_entry)) {
650 return FAILURE;
651 }
652
653 obj = PSI_OBJ(iarg->_zv, NULL);
654 arg_val->ptr = obj->data;
655 }
656 break;
657 EMPTY_SWITCH_DEFAULT_CASE();
658 }
659 return SUCCESS;
660 }
661
662 static inline void *psi_do_let(let_stmt *let)
663 {
664 decl_arg *darg = let->var->arg;
665 impl_val *arg_val = darg->ptr;
666 impl_arg *iarg;
667
668 switch (let->val ? let->val->kind : PSI_LET_NULL) {
669 case PSI_LET_TMP:
670 arg_val->ptr = deref_impl_val(let->val->data.var->arg->val.ptr, let->var);
671 break;
672 case PSI_LET_NULL:
673 if (darg->var->array_size) {
674 arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val));
675 darg->mem = arg_val->ptr;
676 } else {
677 memset(arg_val, 0, sizeof(*arg_val));
678 }
679 break;
680 case PSI_LET_CALLOC:
681 arg_val->ptr = psi_do_calloc(let->val->data.alloc);
682 darg->mem = arg_val->ptr;
683 break;
684 case PSI_LET_NUMEXP:
685 arg_val->zend.lval = psi_long_num_exp(let->val->data.num, NULL);
686 break;
687 case PSI_LET_FUNC:
688 iarg = let->val->data.func->arg;
689
690 if (SUCCESS != psi_let_val(let->val->data.func->type, iarg, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem)) {
691 return NULL;
692 }
693 }
694
695 if (let->val && let->val->flags.one.is_reference) {
696 return let->ptr = &darg->ptr;
697 } else {
698 return let->ptr = darg->ptr;
699 }
700 }
701
702 static inline void psi_do_set(zval *return_value, set_value *set)
703 {
704 zval_dtor(return_value);
705 set->func->handler(return_value, set, set->vars->vars[0]->arg->ptr);
706 }
707
708 static inline void psi_do_return(zval *return_value, return_stmt *ret)
709 {
710 ret->set->func->handler(return_value, ret->set, ret->set->vars->vars[0]->arg->ptr);
711 }
712
713 static inline void psi_do_free(free_stmt *fre)
714 {
715 size_t i, j;
716
717 for (i = 0; i < fre->calls->count; ++i) {
718 free_call *f = fre->calls->list[i];
719
720 for (j = 0; j < f->vars->count; ++j) {
721 decl_var *dvar = f->vars->vars[j];
722 decl_arg *darg = dvar->arg;
723
724 f->decl->call.args[j] = &darg->val;
725 }
726
727 /* FIXME: check in validate_* that free functions return scalar */
728 PSI_ContextCall(&PSI_G(context), &f->decl->call, NULL);
729 }
730 }
731
732 static inline void psi_do_clean(impl *impl)
733 {
734 size_t i;
735
736 for (i = 0; i < impl->func->args->count; ++i ) {
737 impl_arg *iarg = impl->func->args->args[i];
738
739 switch (iarg->type->type) {
740 case PSI_T_STRING:
741 if (iarg->val.zend.str) {
742 zend_string_release(iarg->val.zend.str);
743 }
744 break;
745 }
746 }
747
748 if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
749 decl_arg *darg = impl->decl->args->args[i];
750
751 if (darg->mem) {
752 decl_type *type = real_decl_type(darg->type);
753
754 if (type->type == PSI_T_STRUCT) {
755 void **ptr = (void **) ((char *) darg->mem + type->strct->size);
756
757 while (*ptr) {
758 efree(*ptr++);
759 }
760 }
761 efree(darg->mem);
762 darg->mem = NULL;
763 }
764 }
765
766 if (impl->func->args->vararg.args) {
767 free_impl_args(impl->func->args->vararg.args);
768 impl->func->args->vararg.args = NULL;
769 }
770 if (impl->func->args->vararg.types) {
771 efree(impl->func->args->vararg.types);
772 impl->func->args->vararg.types = NULL;
773 }
774 if (impl->func->args->vararg.values) {
775 efree(impl->func->args->vararg.values);
776 impl->func->args->vararg.values = NULL;
777 }
778 if (impl->func->args->vararg.free_list) {
779 void **list = impl->func->args->vararg.free_list;
780
781 while (*list) {
782 efree(*list++);
783 }
784
785 efree(impl->func->args->vararg.free_list);
786 impl->func->args->vararg.free_list = NULL;
787 }
788 }
789
790 static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *strct, impl_val *res) {
791 impl_val *ref, *tmp = NULL;
792
793 switch (exp->t) {
794 case PSI_T_NUMBER:
795 switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) res, (double *) res, 0)) {
796 case IS_LONG:
797 return PSI_T_INT64;
798 case IS_DOUBLE:
799 return PSI_T_DOUBLE;
800 }
801 break;
802
803 case PSI_T_NSNAME:
804 switch (exp->u.cnst->type->type) {
805 case PSI_T_INT:
806 res->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval;
807 return PSI_T_INT64;
808 case PSI_T_FLOAT:
809 res->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval;
810 return PSI_T_DOUBLE;
811 default:
812 return 0;
813 }
814 break;
815
816 case PSI_T_NAME:
817 if (strct) {
818 ref = struct_member_ref(exp->u.dvar->arg, strct, &tmp);
819 } else {
820 ref = exp->u.dvar->arg->ptr;
821 }
822 switch (real_decl_type(exp->u.dvar->arg->type)->type) {
823 case PSI_T_INT8:
824 case PSI_T_UINT8:
825 case PSI_T_INT16:
826 case PSI_T_UINT16:
827 case PSI_T_INT32:
828 case PSI_T_UINT32:
829 case PSI_T_INT64:
830 case PSI_T_UINT64:
831 memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
832 if (tmp) {
833 free(tmp);
834 }
835 return real_decl_type(exp->u.dvar->arg->type)->type;
836
837 case PSI_T_FLOAT:
838 case PSI_T_DOUBLE:
839 memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
840 if (tmp) {
841 free(tmp);
842 }
843 return real_decl_type(exp->u.dvar->arg->type)->type;
844
845 EMPTY_SWITCH_DEFAULT_CASE();
846 }
847 break;
848
849 EMPTY_SWITCH_DEFAULT_CASE();
850 }
851 return 0;
852 }
853
854 int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) {
855 impl_val num = {0};
856 int num_type = psi_calc_num_exp_value(exp, strct, &num);
857
858 if (exp->operand) {
859 impl_val tmp = {0};
860 int tmp_type = psi_calc_num_exp(exp->operand, strct, &tmp);
861
862 return exp->calculator(num_type, &num, tmp_type, &tmp, res);
863 }
864
865 memcpy(res, &num, sizeof(*res));
866 return num_type;
867 }
868
869 #define PRIfval "f"
870 #define PRIdval "lf"
871
872 #define PSI_CALC_OP(var) do { \
873 const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
874 res->var = PSI_CALC(v1->var, v2->var); \
875 if (!res->var) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
876 } while (0)
877 #define PSI_CALC_OP2(vres, var1, var2) do { \
878 const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \
879 res->vres = PSI_CALC(v1->var1, v2->var2); \
880 if (!res->vres) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
881 } while(0)
882 #define PSI_CALC_FN(op) int psi_calc_##op(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res) \
883 { \
884 if (t1 == t2) { \
885 switch (t1) { \
886 case PSI_T_FLOAT: PSI_CALC_OP(fval); break; \
887 case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; \
888 case PSI_T_INT8: PSI_CALC_OP(i8); break; \
889 case PSI_T_UINT8: PSI_CALC_OP(u8); break; \
890 case PSI_T_INT16: PSI_CALC_OP(i16); break; \
891 case PSI_T_UINT16: PSI_CALC_OP(u16); break; \
892 case PSI_T_INT32: PSI_CALC_OP(i32); break; \
893 case PSI_T_UINT32: PSI_CALC_OP(u32); break; \
894 case PSI_T_INT64: PSI_CALC_OP(i64); break; \
895 case PSI_T_UINT64: PSI_CALC_OP(u64); break; \
896 EMPTY_SWITCH_DEFAULT_CASE(); \
897 } \
898 return t1; \
899 } else if (t1 == PSI_T_DOUBLE) { \
900 switch (t2) { \
901 case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; \
902 case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; \
903 case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; \
904 case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; \
905 case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; \
906 case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; \
907 case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; \
908 case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; \
909 case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; \
910 EMPTY_SWITCH_DEFAULT_CASE(); \
911 } \
912 return t1; \
913 } else if (t2 == PSI_T_DOUBLE) { \
914 switch (t1) { \
915 case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; \
916 case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; \
917 case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; \
918 case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; \
919 case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; \
920 case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; \
921 case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; \
922 case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; \
923 case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; \
924 EMPTY_SWITCH_DEFAULT_CASE(); \
925 } \
926 return t2; \
927 } else if (t1 == PSI_T_FLOAT) { \
928 switch (t2) { \
929 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; \
930 case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; \
931 case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; \
932 case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; \
933 case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; \
934 case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; \
935 case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; \
936 case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; \
937 case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; \
938 EMPTY_SWITCH_DEFAULT_CASE(); \
939 } \
940 return t1; \
941 } else if (t2 == PSI_T_FLOAT) { \
942 switch (t1) { \
943 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; \
944 case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; \
945 case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; \
946 case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; \
947 case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; \
948 case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; \
949 case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; \
950 case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; \
951 case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; \
952 EMPTY_SWITCH_DEFAULT_CASE(); \
953 } \
954 return t2; \
955 } else { \
956 int64_t sval1 = v1->i64, sval2 = v2->i64; \
957 uint64_t uval1 = v1->u64, uval2 = v2->u64; \
958 switch (t1) { \
959 case PSI_T_INT8: sval1 >>= 8; \
960 case PSI_T_INT16: sval1 >>= 8; \
961 case PSI_T_INT32: sval1 >>= 8; \
962 case PSI_T_INT64: \
963 switch (t2) { \
964 case PSI_T_INT8: sval2 >>= 8; \
965 case PSI_T_INT16: sval2 >>= 8; \
966 case PSI_T_INT32: sval2 >>= 8; \
967 case PSI_T_INT64: \
968 res->i64 = PSI_CALC(sval1 , sval2); \
969 return PSI_T_INT64; \
970 case PSI_T_UINT8: uval2 >>= 8; \
971 case PSI_T_UINT16: uval2 >>= 8; \
972 case PSI_T_UINT32: uval2 >>= 8; \
973 case PSI_T_UINT64: \
974 res->i64 = PSI_CALC(sval1, uval2); \
975 return PSI_T_INT64; \
976 } \
977 break; \
978 case PSI_T_UINT8: uval1 >>= 8; \
979 case PSI_T_UINT16: uval1 >>= 8; \
980 case PSI_T_UINT32: uval1 >>= 8; \
981 case PSI_T_UINT64: \
982 switch (t2) { \
983 case PSI_T_INT8: sval2 >>= 8; \
984 case PSI_T_INT16: sval2 >>= 8; \
985 case PSI_T_INT32: sval2 >>= 8; \
986 case PSI_T_INT64: \
987 res->i64 = PSI_CALC(uval1, sval2); \
988 return PSI_T_INT64; \
989 case PSI_T_UINT8: uval2 >>= 8; \
990 case PSI_T_UINT16: uval2 >>= 8; \
991 case PSI_T_UINT32: uval2 >>= 8; \
992 case PSI_T_UINT64: \
993 res->u64 = PSI_CALC(uval1, uval2); \
994 return PSI_T_UINT64; \
995 } \
996 break; \
997 } \
998 } \
999 ZEND_ASSERT(0); \
1000 return 0; \
1001 }
1002
1003 #undef PSI_CALC
1004 #define PSI_CALC(var1, var2) (var1) + (var2)
1005 PSI_CALC_FN(add)
1006 #undef PSI_CALC
1007 #define PSI_CALC(var1, var2) (var1) * (var2)
1008 PSI_CALC_FN(mul)
1009 #undef PSI_CALC
1010 #define PSI_CALC(var1, var2) (var1) - (var2)
1011 PSI_CALC_FN(sub)
1012 #undef PSI_CALC
1013 #define PSI_CALC(var1, var2) (var1) / (var2)
1014 PSI_CALC_FN(div)
1015
1016 static inline void psi_do_args(impl *impl) {
1017 size_t i;
1018
1019 for (i = 0; i < impl->decl->args->count; ++i) {
1020 impl->decl->call.args[i] = impl->decl->args->args[i]->let->ptr;
1021 }
1022 }
1023
1024 static inline impl_vararg *psi_do_varargs(impl *impl) {
1025 size_t i, j;
1026 impl_vararg *va = &impl->func->args->vararg;
1027 size_t vacount = va->args->count;
1028
1029
1030 if (!vacount) {
1031 return NULL;
1032 }
1033
1034 va->types = ecalloc(vacount, sizeof(*va->types));
1035 va->values = ecalloc(vacount, sizeof(*va->values));
1036
1037 for (i = 0, j = 0; i < vacount; ++i) {
1038 impl_arg *vaarg = va->args->args[i];
1039 void *to_free = NULL;
1040 token_t let_fn, vatype = va->name->type->type;
1041
1042 if (vatype == PSI_T_MIXED) {
1043 switch (Z_TYPE_P(vaarg->_zv)) {
1044 case IS_TRUE:
1045 case IS_FALSE: vatype = PSI_T_BOOL; break;
1046 case IS_LONG: vatype = PSI_T_INT; break;
1047 case IS_DOUBLE: vatype = PSI_T_FLOAT; break;
1048 default: vatype = PSI_T_STRING; break;
1049 }
1050 }
1051
1052
1053 switch (vatype) {
1054 case PSI_T_BOOL: let_fn = PSI_T_BOOLVAL; break;
1055 case PSI_T_INT: let_fn = PSI_T_INTVAL; break;
1056 case PSI_T_FLOAT:
1057 case PSI_T_DOUBLE: let_fn = PSI_T_FLOATVAL;break;
1058 case PSI_T_STRING: let_fn = PSI_T_STRVAL; break;
1059 EMPTY_SWITCH_DEFAULT_CASE();
1060 }
1061
1062 va->types[i] = vatype;
1063 psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free);
1064
1065 if (to_free) {
1066 if (!va->free_list) {
1067 va->free_list = ecalloc(vacount - i + 1, sizeof(*va->free_list));
1068 }
1069 va->free_list[j++] = to_free;
1070 }
1071 }
1072
1073 return va;
1074 }
1075
1076 void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl)
1077 {
1078 size_t i;
1079 impl_vararg *va = NULL;
1080
1081 memset(impl->decl->func->ptr, 0, sizeof(impl_val));
1082
1083 if (SUCCESS != psi_parse_args(execute_data, impl)) {
1084 return;
1085 }
1086
1087 for (i = 0; i < impl->stmts->let.count; ++i) {
1088 let_stmt *let = impl->stmts->let.list[i];
1089
1090 if (!psi_do_let(let)) {
1091 psi_do_return(return_value, impl->stmts->ret.list[0]);
1092 psi_do_clean(impl);
1093 return;
1094 }
1095 }
1096
1097 if (impl->decl->args) {
1098 psi_do_args(impl);
1099
1100 if (impl->func->args->vararg.args) {
1101 va = psi_do_varargs(impl);
1102 }
1103 }
1104
1105 PSI_ContextCall(&PSI_G(context), &impl->decl->call, va);
1106 psi_do_return(return_value, impl->stmts->ret.list[0]);
1107
1108 for (i = 0; i < impl->stmts->set.count; ++i) {
1109 set_stmt *set = impl->stmts->set.list[i];
1110
1111 if (set->arg->_zv) {
1112 psi_do_set(set->arg->_zv, set->val);
1113 }
1114 }
1115
1116 for (i = 0; i < impl->stmts->fre.count; ++i) {
1117 free_stmt *fre = impl->stmts->fre.list[i];
1118
1119 psi_do_free(fre);
1120 }
1121 psi_do_clean(impl);
1122 }
1123
1124 static void psi_object_free(zend_object *o)
1125 {
1126 psi_object *obj = PSI_OBJ(NULL, o);
1127
1128 if (obj->data) {
1129 // free(obj->data);
1130 obj->data = NULL;
1131 }
1132 zend_object_std_dtor(o);
1133 }
1134
1135 static zend_object *psi_object_init(zend_class_entry *ce)
1136 {
1137 psi_object *o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
1138
1139 zend_object_std_init(&o->std, ce);
1140 object_properties_init(&o->std, ce);
1141 o->std.handlers = &psi_object_handlers;
1142 return &o->std;
1143 }
1144
1145 PHP_MINIT_FUNCTION(psi)
1146 {
1147 PSI_ContextOps *ops = NULL;
1148 zend_class_entry ce = {0};
1149
1150 REGISTER_INI_ENTRIES();
1151
1152 INIT_NS_CLASS_ENTRY(ce, "psi", "object", NULL);
1153 psi_class_entry = zend_register_internal_class_ex(&ce, NULL);
1154 psi_class_entry->create_object = psi_object_init;
1155
1156 memcpy(&psi_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1157 psi_object_handlers.offset = XtOffsetOf(psi_object, std);
1158 psi_object_handlers.free_obj = psi_object_free;
1159 psi_object_handlers.clone_obj = NULL;
1160
1161 #ifdef HAVE_LIBJIT
1162 if (!strcasecmp(PSI_G(engine), "jit")) {
1163 ops = PSI_Libjit();
1164 } else
1165 #endif
1166 #ifdef HAVE_LIBFFI
1167 ops = PSI_Libffi();
1168 #endif
1169
1170 if (!ops) {
1171 php_error(E_WARNING, "No PSI engine found");
1172 return FAILURE;
1173 }
1174
1175 PSI_ContextInit(&PSI_G(context), ops, psi_error);
1176 PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
1177
1178 if (psi_check_env("PSI_DUMP")) {
1179 PSI_ContextDump(&PSI_G(context), STDOUT_FILENO);
1180 }
1181
1182 return SUCCESS;
1183 }
1184
1185 PHP_MSHUTDOWN_FUNCTION(psi)
1186 {
1187 PSI_ContextDtor(&PSI_G(context));
1188
1189 UNREGISTER_INI_ENTRIES();
1190
1191 return SUCCESS;
1192 }
1193
1194 #if defined(COMPILE_DL_PSI) && defined(ZTS)
1195 PHP_RINIT_FUNCTION(psi)
1196 {
1197 ZEND_TSRMLS_CACHE_UPDATE();
1198 return SUCCESS;
1199 }
1200 #endif
1201
1202 PHP_MINFO_FUNCTION(psi)
1203 {
1204 php_info_print_table_start();
1205 php_info_print_table_header(2, "psi support", "enabled");
1206 php_info_print_table_end();
1207
1208 DISPLAY_INI_ENTRIES();
1209 }
1210 const zend_function_entry psi_functions[] = {
1211 PHP_FE_END
1212 };
1213
1214 zend_module_entry psi_module_entry = {
1215 STANDARD_MODULE_HEADER,
1216 "psi",
1217 psi_functions,
1218 PHP_MINIT(psi),
1219 PHP_MSHUTDOWN(psi),
1220 #if defined(COMPILE_DL_PSI) && defined(ZTS)
1221 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
1222 #else
1223 NULL,
1224 #endif
1225 NULL,
1226 PHP_MINFO(psi),
1227 PHP_PSI_VERSION,
1228 STANDARD_MODULE_PROPERTIES
1229 };
1230
1231 #ifdef COMPILE_DL_PSI
1232 #ifdef ZTS
1233 ZEND_TSRMLS_CACHE_DEFINE();
1234 #endif
1235 ZEND_GET_MODULE(psi)
1236 #endif
1237
1238 /*
1239 * Local variables:
1240 * tab-width: 4
1241 * c-basic-offset: 4
1242 * End:
1243 * vim600: noet sw=4 ts=4 fdm=marker
1244 * vim<600: noet sw=4 ts=4
1245 */