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