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