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