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
11 #include "php_psi.h"
12 #include "parser.h"
13
14 #if HAVE_LIBJIT
15 # include "libjit.h"
16 # ifndef HAVE_LIBFFI
17 # define PSI_ENGINE "jit"
18 # endif
19 #endif
20 #if HAVE_LIBFFI
21 # include "libffi.h"
22 # define PSI_ENGINE "ffi"
23 #endif
24
25 ZEND_DECLARE_MODULE_GLOBALS(psi);
26
27 PHP_INI_BEGIN()
28 STD_PHP_INI_ENTRY("psi.engine", PSI_ENGINE, PHP_INI_SYSTEM, OnUpdateString, engine, zend_psi_globals, psi_globals)
29 STD_PHP_INI_ENTRY("psi.directory", "psi.d", PHP_INI_SYSTEM, OnUpdateString, directory, zend_psi_globals, psi_globals)
30 PHP_INI_END();
31
32 static zend_object_handlers psi_object_handlers;
33 static zend_class_entry *psi_class_entry;
34
35 void psi_error(int type, const char *msg, ...)
36 {
37 char buf[0x1000];
38 va_list argv;
39
40 va_start(argv, msg);
41 vslprintf(buf, 0x1000, msg, argv);
42 va_end(argv);
43
44 php_error(type, buf);
45 }
46
47 size_t psi_t_alignment(token_t t)
48 {
49 #define PSI_ALIGNOF(T) case PSI_T_## T: return ALIGNOF_## T ##_T;
50 switch (t) {
51 PSI_ALIGNOF(INT8);
52 PSI_ALIGNOF(UINT8);
53 PSI_ALIGNOF(INT16);
54 PSI_ALIGNOF(UINT16);
55 PSI_ALIGNOF(INT32);
56 PSI_ALIGNOF(UINT32);
57 PSI_ALIGNOF(INT64);
58 PSI_ALIGNOF(UINT64);
59 case PSI_T_FLOAT:
60 return ALIGNOF_FLOAT;
61 case PSI_T_DOUBLE:
62 return ALIGNOF_DOUBLE;
63 case PSI_T_POINTER:
64 return ALIGNOF_VOID_P;
65 EMPTY_SWITCH_DEFAULT_CASE();
66 }
67 }
68
69 size_t psi_t_size(token_t t)
70 {
71 #define PSI_SIZEOF(T) case PSI_T_## T : return SIZEOF_## T ##_T;
72 switch (t) {
73 PSI_SIZEOF(INT8);
74 PSI_SIZEOF(UINT8);
75 PSI_SIZEOF(INT16);
76 PSI_SIZEOF(UINT16);
77 PSI_SIZEOF(INT32);
78 PSI_SIZEOF(UINT32);
79 PSI_SIZEOF(INT64);
80 PSI_SIZEOF(UINT64);
81 case PSI_T_FLOAT:
82 return SIZEOF_FLOAT;
83 case PSI_T_DOUBLE:
84 return SIZEOF_DOUBLE;
85 case PSI_T_POINTER:
86 return SIZEOF_VOID_P;
87 EMPTY_SWITCH_DEFAULT_CASE();
88 }
89 }
90
91 size_t psi_t_align(token_t t, size_t s)
92 {
93 size_t a = psi_t_alignment(t);
94 return ((s - 1) | (a - 1)) + 1;
95 }
96
97 int psi_internal_type(impl_type *type)
98 {
99 switch (type->type) {
100 case PSI_T_BOOL:
101 return _IS_BOOL;
102 case PSI_T_INT:
103 return IS_LONG;
104 case PSI_T_FLOAT:
105 case PSI_T_DOUBLE:
106 return IS_DOUBLE;
107 case PSI_T_STRING:
108 return IS_STRING;
109 case PSI_T_ARRAY:
110 return IS_ARRAY;
111 default:
112 return 0;
113 }
114 }
115
116 zend_internal_arg_info *psi_internal_arginfo(impl *impl)
117 {
118 size_t i;
119 zend_internal_arg_info *aip;
120 zend_internal_function_info *fi;
121
122 aip = calloc(impl->func->args->count + 1, sizeof(*aip));
123
124 fi = (zend_internal_function_info *) &aip[0];
125 fi->required_num_args = psi_num_min_args(impl);
126 fi->return_reference = impl->func->return_reference;
127 fi->type_hint = psi_internal_type(impl->func->return_type);
128
129 for (i = 0; i < impl->func->args->count; ++i) {
130 impl_arg *iarg = impl->func->args->args[i];
131 zend_internal_arg_info *ai = &aip[i+1];
132
133 ai->name = iarg->var->name;
134 ai->type_hint = psi_internal_type(iarg->type);
135 if (iarg->var->reference) {
136 ai->pass_by_reference = 1;
137 }
138 if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
139 ai->allow_null = 1;
140 }
141 }
142
143 return aip;
144 }
145
146 size_t psi_num_min_args(impl *impl)
147 {
148 size_t i, n = impl->func->args->count;
149
150 for (i = 0; i < impl->func->args->count; ++i) {
151 if (impl->func->args->args[i]->def) {
152 --n;
153 }
154 }
155 return n;
156 }
157
158 void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val)
159 {
160 RETVAL_NULL();
161 }
162
163 void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val)
164 {
165 psi_to_int(return_value, set, ret_val);
166 convert_to_boolean(return_value);
167 }
168
169 void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val)
170 {
171 decl_var *var = set->vars->vars[0];
172 token_t t = real_decl_type(var->arg->type)->type;
173 impl_val *v = deref_impl_val(ret_val, var);
174
175 switch (t) {
176 case PSI_T_FLOAT:
177 RETVAL_DOUBLE((double) v->fval);
178 convert_to_long(return_value);
179 break;
180 case PSI_T_DOUBLE:
181 RETVAL_DOUBLE(v->dval);
182 convert_to_long(return_value);
183 break;
184 case PSI_T_INT8:
185 RETVAL_LONG(v->i8);
186 break;
187 case PSI_T_UINT8:
188 RETVAL_LONG(v->u8);
189 break;
190 case PSI_T_INT16:
191 RETVAL_LONG(v->i16);
192 break;
193 case PSI_T_UINT16:
194 RETVAL_LONG(v->u16);
195 break;
196 case PSI_T_INT32:
197 RETVAL_LONG(v->i32);
198 break;
199 case PSI_T_UINT32:
200 #if UINT32_MAX >= ZEND_LONG_MAX
201 if (v->u32 > ZEND_LONG_MAX) {
202 char d[12] = {0};
203
204 RETVAL_STRING(zend_print_ulong_to_buf(&d[10], v->u32));
205 } else {
206 #endif
207 RETVAL_LONG(v->u32);
208 #if UINT32_MAX >= ZEND_LONG_MAX
209 }
210 #endif
211 break;
212 case PSI_T_INT64:
213 RETVAL_LONG(v->i64);
214 break;
215 case PSI_T_UINT64:
216 if (v->u64 > ZEND_LONG_MAX) {
217 char d[24] = {0};
218
219 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], v->u64));
220 } else {
221 RETVAL_LONG(v->u64);
222 }
223 break;
224 EMPTY_SWITCH_DEFAULT_CASE();
225 }
226 }
227
228 void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val)
229 {
230 decl_var *var = set->vars->vars[0];
231 token_t t = real_decl_type(var->arg->type)->type;
232 impl_val *v = deref_impl_val(ret_val, var);
233
234 switch (t) {
235 case PSI_T_FLOAT:
236 RETVAL_DOUBLE((double) v->fval);
237 break;
238 case PSI_T_DOUBLE:
239 RETVAL_DOUBLE(v->dval);
240 break;
241 case PSI_T_INT8:
242 RETVAL_DOUBLE((double) v->i8);
243 break;
244 case PSI_T_UINT8:
245 RETVAL_DOUBLE((double) v->u8);
246 break;
247 case PSI_T_INT16:
248 RETVAL_DOUBLE((double) v->i16);
249 break;
250 case PSI_T_UINT16:
251 RETVAL_DOUBLE((double) v->u16);
252 break;
253 case PSI_T_INT32:
254 RETVAL_DOUBLE((double) v->i32);
255 break;
256 case PSI_T_UINT32:
257 RETVAL_DOUBLE((double) v->u32);
258 break;
259 case PSI_T_INT64:
260 RETVAL_DOUBLE((double) v->i64);
261 break;
262 case PSI_T_UINT64:
263 RETVAL_DOUBLE((double) v->u64);
264 break;
265 EMPTY_SWITCH_DEFAULT_CASE();
266 }
267 }
268
269 void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val)
270 {
271 decl_var *var = set->vars->vars[0];
272 token_t t = real_decl_type(var->arg->type)->type;
273
274 switch (t) {
275 case PSI_T_VOID:
276 case PSI_T_INT8:
277 case PSI_T_UINT8:
278 if (!var->arg->var->pointer_level) {
279 RETVAL_STRINGL(&ret_val->cval, 1);
280 } else {
281 ret_val = deref_impl_val(ret_val, var);
282 if (ret_val && ret_val->ptr) {
283 RETVAL_STRING(ret_val->ptr);
284 } else {
285 RETVAL_EMPTY_STRING();
286 }
287 }
288 return;
289 case PSI_T_FLOAT:
290 RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval);
291 break;
292 case PSI_T_DOUBLE:
293 RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval);
294 break;
295 default:
296 psi_to_int(return_value, set, ret_val);
297 break;
298 }
299 convert_to_string(return_value);
300 }
301
302
303 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
304 {
305 memset(tmp, 0, sizeof(*tmp));
306 memcpy(tmp, ((void*) val->ptr) + size * i, size);
307 return tmp;
308 }
309
310 void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
311 {
312 decl_type *type = real_decl_type(spec->type);
313
314 switch (type->type) {
315 case PSI_T_FLOAT:
316 mem->fval = (float) zval_get_double(zv);
317 break;
318 case PSI_T_DOUBLE:
319 mem->dval = zval_get_double(zv);
320 break;
321 case PSI_T_INT8:
322 case PSI_T_UINT8:
323 if (spec->var->pointer_level) {
324 zend_string *zs = zval_get_string(zv);
325 *tmp = mem->ptr = estrndup(zs->val, zs->len);
326 zend_string_release(zs);
327 break;
328 }
329 /* no break */
330 default:
331 mem->zend.lval = zval_get_long(zv);
332 break;
333 }
334 }
335
336 void *psi_array_to_struct(decl_struct *s, HashTable *arr)
337 {
338 size_t i, j = 0;
339 char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *));
340
341 if (arr) for (i = 0; i < s->args->count; ++i) {
342 decl_arg *darg = s->args->args[i];
343 zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
344
345 if (entry) {
346 impl_val val;
347 void *tmp = NULL;
348
349 memset(&tmp, 0, sizeof(tmp));
350 psi_from_zval(&val, darg, entry, &tmp);
351 memcpy(mem + darg->layout->pos, &val, darg->layout->len);
352 if (tmp) {
353 ((void **)(mem + s->size))[j++] = tmp;
354 }
355 }
356 }
357 return mem;
358 }
359
360 static inline impl_val *struct_member_ref(decl_arg *set_arg, impl_val *struct_ptr, impl_val **to_free) {
361 void *ptr = (char *) struct_ptr->ptr + set_arg->layout->pos;
362 impl_val *val = enref_impl_val(ptr, set_arg->var);
363
364 if (val != ptr) {
365 *to_free = val;
366 }
367
368 return val;
369 }
370 void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
371 {
372 size_t i;
373 decl_var *var = set->vars->vars[0];
374 token_t t = real_decl_type(var->arg->type)->type;
375 impl_val tmp, *ret_val = deref_impl_val(r_val, var);
376
377 array_init(return_value);
378
379 if (t == PSI_T_STRUCT) {
380 // decl_struct *s = real_decl_type(var->arg->type)->strct;
381
382 if (set->count) {
383 /* explicit member casts */
384 for (i = 0; i < set->count; ++i) {
385 set_value *sub_set = set->inner[i];
386 decl_var *sub_var = sub_set->vars->vars[0];
387
388 sub_set->outer.val = r_val;
389
390 if (sub_var->arg) {
391 impl_val *tmp = NULL, *val;
392 zval ztmp;
393
394 val = deref_impl_val(struct_member_ref(sub_var->arg, ret_val, &tmp), sub_var);
395 sub_set->func->handler(&ztmp, sub_set, val);
396 add_assoc_zval(return_value, sub_var->name, &ztmp);
397
398 if (tmp) {
399 free(tmp);
400 }
401 }
402 }
403 }
404 return;
405 }
406
407 if (var->arg->var->array_size) {
408 /* to_array(foo[NUMBER]) */
409 for (i = 0; i < var->arg->var->array_size; ++i) {
410 size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t);
411 impl_val *ptr = iterate(ret_val, size, i, &tmp);
412 zval ele;
413
414 switch (t) {
415 case PSI_T_FLOAT:
416 ZVAL_DOUBLE(&ele, (double) ptr->fval);
417 break;
418 case PSI_T_DOUBLE:
419 ZVAL_DOUBLE(&ele, ptr->dval);
420 break;
421 default:
422 ZVAL_LONG(&ele, ptr->lval);
423 break;
424 }
425
426 add_next_index_zval(return_value, &ele);
427 }
428 return;
429 } else if (set->vars->count > 1) {
430 /* to_array(arr_var, cnt_var[, cnt_var...], to_int(*arr_var))
431 * check for length in second var
432 */
433 size_t count = 0;
434 zval ele;
435
436 if (set->outer.set) {
437 /* struct */
438 for (i = 1; i < set->vars->count; ++i) {
439 impl_val *tmp = NULL, *cnt_val;
440 decl_var *cnt_var = set->vars->vars[i];
441
442 cnt_val = struct_member_ref(cnt_var->arg, set->outer.val, &tmp);
443 count += deref_impl_val(cnt_val, cnt_var)->lval;
444
445 if (tmp) {
446 free(tmp);
447 }
448 }
449 } else {
450 ZEND_ASSERT(0);
451 }
452
453 for (i = 0; i < count; ++i) {
454 size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
455 impl_val *ptr = iterate(ret_val, size, i, &tmp);
456
457 set->inner[0]->func->handler(&ele, set->inner[0], ptr);
458 add_next_index_zval(return_value, &ele);
459 }
460 } else {
461 ZEND_ASSERT(0);
462 }
463 }
464
465 void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
466 {
467 decl_var *var = set->vars->vars[0];
468 impl_val *ret_val = deref_impl_val(r_val, var);
469 psi_object *obj;
470
471 if (ret_val->ptr) {
472 object_init_ex(return_value, psi_class_entry);
473 obj = PSI_OBJ(return_value, NULL);
474 obj->data = ret_val->ptr;
475 } else {
476 RETVAL_NULL();
477 }
478 }
479
480 static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
481 {
482 impl_arg *iarg;
483 zend_error_handling zeh;
484
485 zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh);
486
487 if (!impl->func->args->count) {
488 ZEND_RESULT_CODE rv;
489
490 rv = zend_parse_parameters_none();
491 zend_restore_error_handling(&zeh);
492 return rv;
493 }
494
495 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->count)
496 nextarg:
497 iarg = impl->func->args->args[_i];
498 if (iarg->def) {
499 Z_PARAM_OPTIONAL;
500 }
501 if (PSI_T_BOOL == iarg->type->type) {
502 if (iarg->def) {
503 iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
504 }
505 Z_PARAM_BOOL(iarg->val.zend.bval);
506 } else if (PSI_T_INT == iarg->type->type) {
507 if (iarg->def) {
508 iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
509 }
510 Z_PARAM_LONG(iarg->val.zend.lval);
511 } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
512 if (iarg->def) {
513 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
514 }
515 Z_PARAM_DOUBLE(iarg->val.dval);
516 } else if (PSI_T_STRING == iarg->type->type) {
517 struct {char *val; size_t len;} str;
518 if (iarg->def) {
519 /* FIXME */
520 str.len = strlen(iarg->def->text) - 2;
521 str.val = &iarg->def->text[1];
522 }
523 Z_PARAM_STR_EX(iarg->val.zend.str, 1, 0);
524 if (iarg->val.zend.str) {
525 zend_string_addref(iarg->val.zend.str);
526 } else if (iarg->def) {
527 iarg->val.zend.str = zend_string_init(str.val, str.len, 0);
528 }
529 } else if (PSI_T_ARRAY == iarg->type->type) {
530 /* handled as _zv in let or set */
531 Z_PARAM_ARRAY_EX(iarg->_zv, 1, 0);
532 } else if (PSI_T_OBJECT == iarg->type->type) {
533 Z_PARAM_OBJECT_EX(iarg->_zv, 1, 0);
534 } else {
535 error_code = ZPP_ERROR_FAILURE;
536 break;
537 }
538 iarg->_zv = _arg;
539 if (_i < _max_num_args) {
540 goto nextarg;
541 }
542 ZEND_PARSE_PARAMETERS_END_EX(
543 zend_restore_error_handling(&zeh);
544 return FAILURE
545 );
546
547 zend_restore_error_handling(&zeh);
548 return SUCCESS;
549 }
550
551 static inline void *psi_do_calloc(let_calloc *alloc)
552 {
553 decl_type *type = real_decl_type(alloc->type);
554 size_t size;
555
556 if (type->type == PSI_T_STRUCT) {
557 /* psi_do_clean expects at least one NULL pointer after the struct */
558 size = type->strct->size + sizeof(void *);
559 } else {
560 size = psi_t_size(type->type);
561 }
562
563 return ecalloc(alloc->n, size);
564 }
565
566 static inline void *psi_do_let(decl_arg *darg)
567 {
568 impl_arg *iarg = darg->let->arg;
569 impl_val *arg_val;
570
571 darg->let->ptr = &darg->let->out;
572 arg_val = darg->let->ptr;
573
574 if (!iarg) {
575 /* let foo = calloc(1, long);
576 * let foo = NULL;
577 * let foo;
578 */
579 if (darg->let->val->func && darg->let->val->func->type == PSI_T_CALLOC) {
580 arg_val->ptr = psi_do_calloc(darg->let->val->func->alloc);
581 darg->let->mem = arg_val->ptr;
582 } else if (darg->var->array_size) {
583 arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val));
584 darg->let->mem = arg_val->ptr;
585 } else {
586 memset(arg_val, 0, sizeof(*arg_val));
587 }
588 } else {
589
590 switch (darg->let->val->func->type) {
591 case PSI_T_BOOLVAL:
592 if (iarg->type->type == PSI_T_BOOL) {
593 arg_val->cval = iarg->val.zend.bval;
594 } else {
595 arg_val->cval = zend_is_true(iarg->_zv);
596 }
597 break;
598 case PSI_T_INTVAL:
599 if (iarg->type->type == PSI_T_INT) {
600 arg_val->lval = iarg->val.zend.lval;
601 } else {
602 arg_val->lval = zval_get_long(iarg->_zv);
603 }
604 break;
605 case PSI_T_PATHVAL:
606 case PSI_T_STRVAL:
607 if (iarg->type->type == PSI_T_STRING) {
608 arg_val->ptr = estrdup(iarg->val.zend.str->val);
609 darg->let->mem = arg_val->ptr;
610 zend_string_release(iarg->val.zend.str);
611 } else {
612 zend_string *zs = zval_get_string(iarg->_zv);
613 arg_val->ptr = estrdup(zs->val);
614 darg->let->mem = arg_val->ptr;
615 zend_string_release(zs);
616 }
617 if (PSI_T_PATHVAL == darg->let->val->func->type) {
618 if (SUCCESS != php_check_open_basedir(arg_val->ptr)) {
619 efree(arg_val->ptr);
620 return NULL;
621 }
622 }
623 break;
624 case PSI_T_STRLEN:
625 if (iarg->type->type == PSI_T_STRING) {
626 arg_val->lval = iarg->val.zend.str->len;
627 zend_string_release(iarg->val.zend.str);
628 } else {
629 zend_string *zs = zval_get_string(iarg->_zv);
630 arg_val->lval = zs->len;
631 zend_string_release(zs);
632 }
633 break;
634 case PSI_T_ARRVAL:
635 if (iarg->type->type == PSI_T_ARRAY) {
636 decl_type *type = real_decl_type(darg->type);
637
638 switch (type->type) {
639 case PSI_T_STRUCT:
640 arg_val->ptr = psi_array_to_struct(type->strct, HASH_OF(iarg->_zv));
641 darg->let->mem = arg_val->ptr;
642 break;
643 }
644 }
645 break;
646 case PSI_T_OBJVAL:
647 if (iarg->type->type == PSI_T_OBJECT) {
648 psi_object *obj;
649
650 if (!instanceof_function(Z_OBJCE_P(iarg->_zv), psi_class_entry)) {
651 return NULL;
652 }
653
654 obj = PSI_OBJ(iarg->_zv, NULL);
655 arg_val->ptr = obj->data;
656 }
657 break;
658 EMPTY_SWITCH_DEFAULT_CASE();
659 }
660 }
661
662 if (darg->let->val && darg->let->val->is_reference) {
663 return &darg->let->ptr;
664 } else {
665 return darg->let->ptr;
666 }
667 }
668
669 static inline void psi_do_set(zval *return_value, set_value *set)
670 {
671 ZVAL_DEREF(return_value);
672 zval_dtor(return_value);
673
674 set->func->handler(return_value, set, set->vars->vars[0]->arg->let->ptr);
675 }
676
677 static inline void psi_do_return(zval *return_value, return_stmt *ret, impl_val *ret_val)
678 {
679 ret->set->func->handler(return_value, ret->set, ret_val);
680 }
681
682 static inline void psi_do_free(free_stmt *fre)
683 {
684 size_t i, j;
685 impl_val dummy;
686
687 for (i = 0; i < fre->calls->count; ++i) {
688 free_call *f = fre->calls->list[i];
689
690 for (j = 0; j < f->vars->count; ++j) {
691 decl_var *dvar = f->vars->vars[j];
692 decl_arg *darg = dvar->arg;
693
694 f->decl->call.args[j] = &darg->let->out;
695 }
696
697 /* FIXME: check in validate_* that free functions return scalar */
698 PSI_ContextCall(&PSI_G(context), &dummy, f->decl);
699 }
700 }
701
702 static inline void psi_do_clean(impl *impl)
703 {
704 size_t i;
705
706 for (i = 0; i < impl->func->args->count; ++i ) {
707 impl_arg *iarg = impl->func->args->args[i];
708
709 switch (iarg->type->type) {
710 case PSI_T_STRING:
711 if (iarg->val.zend.str) {
712 zend_string_release(iarg->val.zend.str);
713 }
714 break;
715 }
716 }
717
718 if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
719 decl_arg *darg = impl->decl->args->args[i];
720
721 if (darg->let && darg->let->mem) {
722 decl_type *type = real_decl_type(darg->type);
723
724 if (type->type == PSI_T_STRUCT) {
725 void **ptr = (void **) ((char *) darg->let->mem + type->strct->size);
726
727 while (*ptr) {
728 efree(*ptr++);
729 }
730 }
731 efree(darg->let->mem);
732 darg->let->mem = NULL;
733 }
734 }
735 }
736
737 void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl)
738 {
739 impl_val ret_val;
740 size_t i;
741
742 if (SUCCESS != psi_parse_args(execute_data, impl)) {
743 return;
744 }
745
746 if (impl->decl->args) {
747 for (i = 0; i < impl->decl->args->count; ++i) {
748 decl_arg *darg = impl->decl->args->args[i];
749
750 if (!(impl->decl->call.args[i] = psi_do_let(darg))) {
751 goto cleanup;
752 }
753 }
754 }
755
756 memset(&ret_val, 0, sizeof(ret_val));
757 PSI_ContextCall(&PSI_G(context), &ret_val, impl->decl);
758
759 psi_do_return(return_value, impl->stmts->ret.list[0], &ret_val);
760
761 for (i = 0; i < impl->stmts->set.count; ++i) {
762 set_stmt *set = impl->stmts->set.list[i];
763
764 if (set->arg->_zv) {
765 psi_do_set(set->arg->_zv, set->val);
766 }
767 }
768
769 for (i = 0; i < impl->stmts->fre.count; ++i) {
770 free_stmt *fre = impl->stmts->fre.list[i];
771
772 psi_do_free(fre);
773 }
774 psi_do_clean(impl);
775 return;
776
777 cleanup:
778 memset(&ret_val, 0, sizeof(ret_val));
779 psi_do_return(return_value, impl->stmts->ret.list[0], &ret_val);
780 psi_do_clean(impl);
781 }
782
783 static void psi_object_free(zend_object *o)
784 {
785 psi_object *obj = PSI_OBJ(NULL, o);
786
787 if (obj->data) {
788 // free(obj->data);
789 obj->data = NULL;
790 }
791 zend_object_std_dtor(o);
792 }
793
794 static zend_object *psi_object_init(zend_class_entry *ce)
795 {
796 psi_object *o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
797
798 zend_object_std_init(&o->std, ce);
799 object_properties_init(&o->std, ce);
800 o->std.handlers = &psi_object_handlers;
801 return &o->std;
802 }
803
804 PHP_MINIT_FUNCTION(psi)
805 {
806 PSI_ContextOps *ops = NULL;
807 zend_class_entry ce = {0};
808
809 REGISTER_INI_ENTRIES();
810
811 INIT_NS_CLASS_ENTRY(ce, "psi", "object", NULL);
812 psi_class_entry = zend_register_internal_class_ex(&ce, NULL);
813 psi_class_entry->create_object = psi_object_init;
814
815 memcpy(&psi_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
816 psi_object_handlers.offset = XtOffsetOf(psi_object, std);
817 psi_object_handlers.free_obj = psi_object_free;
818 psi_object_handlers.clone_obj = NULL;
819
820 #ifdef HAVE_LIBJIT
821 if (!strcasecmp(PSI_G(engine), "jit")) {
822 ops = PSI_Libjit();
823 } else
824 #endif
825 #ifdef HAVE_LIBFFI
826 ops = PSI_Libffi();
827 #endif
828
829 if (!ops) {
830 php_error(E_WARNING, "No PSI engine found");
831 return FAILURE;
832 }
833
834 PSI_ContextInit(&PSI_G(context), ops, psi_error);
835 PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
836
837 if (psi_check_env("PSI_DUMP")) {
838 PSI_ContextDump(&PSI_G(context), STDOUT_FILENO);
839 }
840
841 return SUCCESS;
842 }
843 PHP_MSHUTDOWN_FUNCTION(psi)
844 {
845 PSI_ContextDtor(&PSI_G(context));
846
847 UNREGISTER_INI_ENTRIES();
848
849 return SUCCESS;
850 }
851
852 /* Remove if there's nothing to do at request start */
853 /* {{{ PHP_RINIT_FUNCTION
854 */
855 PHP_RINIT_FUNCTION(psi)
856 {
857 #if defined(COMPILE_DL_PSI) && defined(ZTS)
858 ZEND_TSRMLS_CACHE_UPDATE();
859 #endif
860 return SUCCESS;
861 }
862 /* }}} */
863
864 /* Remove if there's nothing to do at request end */
865 /* {{{ PHP_RSHUTDOWN_FUNCTION
866 */
867 PHP_RSHUTDOWN_FUNCTION(psi)
868 {
869 return SUCCESS;
870 }
871 /* }}} */
872
873 PHP_MINFO_FUNCTION(psi)
874 {
875 php_info_print_table_start();
876 php_info_print_table_header(2, "psi support", "enabled");
877 php_info_print_table_end();
878
879 DISPLAY_INI_ENTRIES();
880 }
881 const zend_function_entry psi_functions[] = {
882 PHP_FE_END
883 };
884
885 zend_module_entry psi_module_entry = {
886 STANDARD_MODULE_HEADER,
887 "psi",
888 psi_functions,
889 PHP_MINIT(psi),
890 PHP_MSHUTDOWN(psi),
891 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
892 PHP_RSHUTDOWN(psi), /* Replace with NULL if there's nothing to do at request end */
893 PHP_MINFO(psi),
894 PHP_PSI_VERSION,
895 STANDARD_MODULE_PROPERTIES
896 };
897
898 #ifdef COMPILE_DL_PSI
899 #ifdef ZTS
900 ZEND_TSRMLS_CACHE_DEFINE();
901 #endif
902 ZEND_GET_MODULE(psi)
903 #endif
904
905 /*
906 * Local variables:
907 * tab-width: 4
908 * c-basic-offset: 4
909 * End:
910 * vim600: noet sw=4 ts=4 fdm=marker
911 * vim<600: noet sw=4 ts=4
912 */