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