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