8 #include "ext/standard/info.h"
16 ZEND_DECLARE_MODULE_GLOBALS(psi
);
19 STD_PHP_INI_ENTRY("psi.engine", "ffi", PHP_INI_SYSTEM
, OnUpdateString
, engine
, zend_psi_globals
, psi_globals
)
20 STD_PHP_INI_ENTRY("psi.directory", "psis", PHP_INI_SYSTEM
, OnUpdateString
, directory
, zend_psi_globals
, psi_globals
)
23 void psi_error(int type
, const char *msg
, ...)
29 vslprintf(buf
, 0x1000, msg
, argv
);
35 int psi_internal_type(impl_type
*type
)
55 zend_internal_arg_info
*psi_internal_arginfo(impl
*impl
)
58 zend_internal_arg_info
*aip
;
59 zend_internal_function_info
*fi
;
61 aip
= calloc(impl
->func
->args
->count
+ 1, sizeof(*aip
));
63 fi
= (zend_internal_function_info
*) &aip
[0];
64 fi
->required_num_args
= psi_num_min_args(impl
);
65 fi
->return_reference
= impl
->func
->return_reference
;
66 fi
->type_hint
= psi_internal_type(impl
->func
->return_type
);
68 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
69 impl_arg
*iarg
= impl
->func
->args
->args
[i
];
70 zend_internal_arg_info
*ai
= &aip
[i
+1];
72 ai
->name
= iarg
->var
->name
;
73 ai
->type_hint
= psi_internal_type(iarg
->type
);
74 if (iarg
->var
->reference
) {
75 ai
->pass_by_reference
= 1;
77 if (iarg
->var
->reference
|| (iarg
->def
&& iarg
->def
->type
== PSI_T_NULL
)) {
85 size_t psi_num_min_args(impl
*impl
)
87 size_t i
, n
= impl
->func
->args
->count
;
89 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
90 if (impl
->func
->args
->args
[i
]->def
) {
97 void psi_to_int(zval
*return_value
, token_t t
, impl_val
*ret_val
, decl_var
*var
)
101 RETVAL_DOUBLE((double) deref_impl_val(ret_val
, var
)->fval
);
102 convert_to_long(return_value
);
105 RETVAL_DOUBLE(deref_impl_val(ret_val
, var
)->dval
);
106 convert_to_long(return_value
);
109 RETVAL_LONG(deref_impl_val(ret_val
, var
)->lval
);
113 void psi_to_double(zval
*return_value
, token_t t
, impl_val
*ret_val
, decl_var
*var
)
117 RETVAL_DOUBLE((double) deref_impl_val(ret_val
, var
)->fval
);
120 RETVAL_DOUBLE(deref_impl_val(ret_val
, var
)->dval
);
123 RETVAL_DOUBLE((double) deref_impl_val(ret_val
, var
)->lval
);
128 void psi_to_string(zval
*return_value
, token_t t
, impl_val
*ret_val
, decl_var
*var
)
134 if (var
->pointer_level
== var
->arg
->var
->pointer_level
) {
135 RETVAL_STRINGL(&ret_val
->cval
, 1);
137 ret_val
= deref_impl_val(ret_val
, var
);
139 RETVAL_STRING(ret_val
->ptr
);
141 RETVAL_EMPTY_STRING();
146 RETVAL_DOUBLE((double) deref_impl_val(ret_val
, var
)->fval
);
147 convert_to_string(return_value
);
150 RETVAL_DOUBLE(deref_impl_val(ret_val
, var
)->dval
);
151 convert_to_string(return_value
);
154 RETVAL_LONG(deref_impl_val(ret_val
, var
)->lval
);
155 convert_to_string(return_value
);
160 size_t psi_t_alignment(token_t t
)
163 #define PSI_TAS_D(T) struct PSI_TAS_ ##T { \
167 #define PSI_TAS_P(T) struct PSI_TAS_ ## T ## _pointer { \
171 #define PSI_TAS_C(T) align = offsetof(struct PSI_TAS_ ##T, x)
172 #define PSI_TAS_CASE(T) { \
181 PSI_TAS_CASE(int8_t);
184 PSI_TAS_CASE(uint8_t);
190 PSI_TAS_CASE(int16_t);
193 PSI_TAS_CASE(uint16_t);
199 PSI_TAS_CASE(int32_t);
202 PSI_TAS_CASE(uint32_t);
208 PSI_TAS_CASE(int64_t);
211 PSI_TAS_CASE(uint64_t);
217 PSI_TAS_CASE(double);
220 PSI_TAS_CASE(size_t);
225 PSI_TAS_C(char_pointer
);
228 EMPTY_SWITCH_DEFAULT_CASE();
234 size_t psi_t_size(token_t t
)
247 size
= sizeof(short);
268 size
= sizeof(float);
271 size
= sizeof(double);
274 size
= sizeof(size_t);
277 size
= sizeof(char *);
279 EMPTY_SWITCH_DEFAULT_CASE();
284 size_t psi_t_align(token_t t
, size_t s
)
286 size_t a
= psi_t_alignment(t
);
287 return ((s
- 1) | (a
- 1)) + 1;
290 static impl_val
*iterate(impl_val
*val
, token_t t
, unsigned i
, impl_val
*tmp
)
292 size_t size
= psi_t_size(t
);
294 memset(tmp
, 0, sizeof(*tmp
));
295 memcpy(tmp
, val
->ptr
+ size
* i
, size
);
299 void psi_from_zval(impl_val
*mem
, decl_arg
*spec
, zval
*zv
, void **tmp
)
301 decl_type
*type
= real_decl_type(spec
->type
);
303 switch (type
->type
) {
305 mem
->fval
= (float) zval_get_double(zv
);
308 mem
->dval
= zval_get_double(zv
);
313 if (spec
->var
->pointer_level
) {
314 zend_string
*zs
= zval_get_string(zv
);
315 *tmp
= mem
->ptr
= estrndup(zs
->val
, zs
->len
);
316 zend_string_release(zs
);
320 mem
->zend
.lval
= zval_get_long(zv
);
325 void *psi_array_to_struct(decl_struct
*s
, HashTable
*arr
)
327 size_t i
, j
= 0, size
= decl_struct_size(s
);
328 char *mem
= ecalloc(1, size
+ s
->args
->count
* sizeof(void *));
330 for (i
= 0; i
< s
->args
->count
; ++i
) {
331 decl_struct_layout
*layout
= &s
->layout
[i
];
332 decl_arg
*darg
= s
->args
->args
[i
];
333 zval
*entry
= zend_hash_str_find_ind(arr
, darg
->var
->name
, strlen(darg
->var
->name
));
339 memset(&tmp
, 0, sizeof(tmp
));
340 psi_from_zval(&val
, darg
, entry
, &tmp
);
341 memcpy(mem
+ layout
->pos
, &val
, layout
->len
);
343 ((void **)(mem
+ size
))[j
++] = tmp
;
350 void psi_to_array(zval
*return_value
, token_t t
, impl_val
*ret_val
, decl_var
*var
)
356 array_init(return_value
);
358 if (t
== PSI_T_STRUCT
) {
359 decl_struct
*s
= real_decl_type(var
->arg
->type
)->strct
;
360 ret_val
= deref_impl_val(ret_val
, var
);
363 for (i
= 0; i
< s
->args
->count
; ++i
) {
364 decl_arg
*darg
= s
->args
->args
[i
];
365 decl_struct_layout layout
= s
->layout
[i
];
368 char *ptr
= (char *) ret_val
->ptr
+ layout
.pos
;
370 memset(&tmp
, 0, sizeof(tmp
));
371 memcpy(&tmp
, ptr
, layout
.len
);
372 switch (real_decl_type(darg
->type
)->type
) {
374 if (darg
->var
->pointer_level
) {
375 psi_to_string(&ztmp
, real_decl_type(darg
->type
)->type
, &tmp
, darg
->var
);
381 psi_to_int(&ztmp
, real_decl_type(darg
->type
)->type
, &tmp
, darg
->var
);
384 printf("t=%d\n", real_decl_type(darg
->type
)->type
);
387 add_assoc_zval(return_value
, darg
->var
->name
, &ztmp
);
391 ret_val
= deref_impl_val(ret_val
, var
);
392 for (i
= 0; i
< var
->arg
->var
->array_size
; ++i
) {
393 impl_val
*ptr
= iterate(ret_val
, t
, i
, &tmp
);
397 ZVAL_DOUBLE(&ele
, (double) ptr
->fval
);
400 ZVAL_DOUBLE(&ele
, ptr
->dval
);
403 ZVAL_LONG(&ele
, ptr
->lval
);
407 add_next_index_zval(return_value
, &ele
);
411 ZEND_RESULT_CODE
psi_parse_args(zend_execute_data
*execute_data
, impl
*impl
)
415 if (!impl
->func
->args
->count
) {
416 return zend_parse_parameters_none();
419 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl
), impl
->func
->args
->count
)
421 iarg
= impl
->func
->args
->args
[_i
];
425 if (PSI_T_BOOL
== iarg
->type
->type
) {
427 iarg
->val
.zend
.bval
= iarg
->def
->type
== PSI_T_TRUE
? 1 : 0;
429 Z_PARAM_BOOL(iarg
->val
.zend
.bval
);
430 } else if (PSI_T_INT
== iarg
->type
->type
|| PSI_T_LONG
== iarg
->type
->type
) {
432 iarg
->val
.zend
.lval
= zend_atol(iarg
->def
->text
, strlen(iarg
->def
->text
));
434 Z_PARAM_LONG(iarg
->val
.zend
.lval
);
435 } else if (PSI_T_FLOAT
== iarg
->type
->type
|| PSI_T_DOUBLE
== iarg
->type
->type
) {
437 iarg
->val
.dval
= zend_strtod(iarg
->def
->text
, NULL
);
439 Z_PARAM_DOUBLE(iarg
->val
.dval
);
440 } else if (PSI_T_STRING
== iarg
->type
->type
) {
441 struct {char *val
; size_t len
;} str
;
444 str
.len
= strlen(iarg
->def
->text
) - 2;
445 str
.val
= &iarg
->def
->text
[1];
447 Z_PARAM_STR_EX(iarg
->val
.zend
.str
, 1, 0);
448 if (iarg
->val
.zend
.str
) {
449 zend_string_addref(iarg
->val
.zend
.str
);
450 } else if (iarg
->def
) {
451 iarg
->val
.zend
.str
= zend_string_init(str
.val
, str
.len
, 0);
453 } else if (PSI_T_ARRAY
== iarg
->type
->type
) {
454 /* handled as _zv in let or set */
457 error_code
= ZPP_ERROR_FAILURE
;
461 if (_i
< _max_num_args
) {
464 ZEND_PARSE_PARAMETERS_END_EX(return FAILURE
);
469 void *psi_do_calloc(let_calloc
*alloc
)
471 decl_type
*type
= real_decl_type(alloc
->type
);
474 if (type
->type
== PSI_T_STRUCT
) {
475 /* psi_do_clean expects a NULL pointer after the struct */
476 size
= decl_struct_size(type
->strct
) + sizeof(void *);
478 size
= psi_t_size(type
->type
);
481 return ecalloc(alloc
->n
, size
);
484 impl_val
*psi_do_let(decl_arg
*darg
)
486 impl_val
*arg_val
= &darg
->let
->out
;
487 impl_arg
*iarg
= darg
->let
->arg
;
490 /* let foo = calloc(1, long);
494 if (darg
->let
->val
->func
->type
== PSI_T_CALLOC
) {
495 arg_val
->ptr
= psi_do_calloc(darg
->let
->val
->func
->alloc
);
496 darg
->let
->mem
= arg_val
->ptr
;
497 } else if (darg
->var
->array_size
) {
498 arg_val
->ptr
= ecalloc(darg
->var
->array_size
, sizeof(*arg_val
));
499 darg
->let
->mem
= arg_val
->ptr
;
501 memset(arg_val
, 0, sizeof(*arg_val
));
506 switch (darg
->let
->val
->func
->type
) {
508 if (iarg
->type
->type
== PSI_T_BOOL
) {
509 arg_val
->cval
= iarg
->val
.zend
.bval
;
511 arg_val
->cval
= zend_is_true(iarg
->_zv
);
515 if (iarg
->type
->type
== PSI_T_INT
|| iarg
->type
->type
== PSI_T_LONG
) {
516 arg_val
->lval
= iarg
->val
.zend
.lval
;
518 arg_val
->lval
= zval_get_long(iarg
->_zv
);
522 if (iarg
->type
->type
== PSI_T_STRING
) {
523 arg_val
->ptr
= estrdup(iarg
->val
.zend
.str
->val
);
524 darg
->let
->mem
= arg_val
->ptr
;
525 zend_string_release(iarg
->val
.zend
.str
);
527 zend_string
*zs
= zval_get_string(iarg
->_zv
);
528 arg_val
->ptr
= estrdup(zs
->val
);
529 darg
->let
->mem
= arg_val
->ptr
;
530 zend_string_release(zs
);
534 if (iarg
->type
->type
== PSI_T_STRING
) {
535 arg_val
->lval
= iarg
->val
.zend
.str
->len
;
536 zend_string_release(iarg
->val
.zend
.str
);
538 zend_string
*zs
= zval_get_string(iarg
->_zv
);
539 arg_val
->lval
= zs
->len
;
540 zend_string_release(zs
);
544 if (iarg
->type
->type
== PSI_T_ARRAY
) {
545 decl_type
*type
= real_decl_type(darg
->type
);
547 switch (type
->type
) {
549 arg_val
->ptr
= psi_array_to_struct(type
->strct
, HASH_OF(iarg
->_zv
));
550 darg
->let
->mem
= arg_val
->ptr
;
555 EMPTY_SWITCH_DEFAULT_CASE();
561 void psi_do_set(zval
*return_value
, set_func
*func
, decl_vars
*vars
)
563 impl_val
*val
= (impl_val
*) &vars
->vars
[0]->arg
->let
->ptr
;
565 ZVAL_DEREF(return_value
);
566 zval_dtor(return_value
);
568 switch (func
->type
) {
569 case PSI_T_TO_STRING
:
570 psi_to_string(return_value
, real_decl_type(vars
->vars
[0]->arg
->type
)->type
, val
, vars
->vars
[0]);
573 psi_to_array(return_value
, real_decl_type(vars
->vars
[0]->arg
->type
)->type
, val
, vars
->vars
[0]);
575 EMPTY_SWITCH_DEFAULT_CASE();
579 void psi_do_return(impl
*impl
, impl_val
*ret_val
, zval
*return_value
)
581 switch (impl
->stmts
->ret
.list
[0]->func
->type
) {
582 case PSI_T_TO_STRING
:
583 psi_to_string(return_value
, real_decl_type(impl
->decl
->func
->type
)->type
, ret_val
, impl
->decl
->func
->var
);
586 psi_to_int(return_value
, real_decl_type(impl
->decl
->func
->type
)->type
, ret_val
, impl
->decl
->func
->var
);
589 psi_to_array(return_value
, real_decl_type(impl
->decl
->func
->type
)->type
, ret_val
, impl
->decl
->func
->var
);
591 EMPTY_SWITCH_DEFAULT_CASE();
595 void psi_do_free(free_stmt
*fre
)
599 for (i
= 0; i
< fre
->vars
->count
; ++i
) {
600 decl_var
*dvar
= fre
->vars
->vars
[i
];
602 if (dvar
->arg
&& dvar
->arg
->let
->out
.ptr
) {
603 free(dvar
->arg
->let
->out
.ptr
);
604 dvar
->arg
->let
->out
.ptr
= NULL
;
609 void psi_do_clean(impl
*impl
)
613 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
614 impl_arg
*iarg
= impl
->func
->args
->args
[i
];
616 switch (iarg
->type
->type
) {
618 if (iarg
->val
.zend
.str
) {
619 zend_string_release(iarg
->val
.zend
.str
);
625 if (impl
->decl
->args
) for (i
= 0; i
< impl
->decl
->args
->count
; ++i
) {
626 decl_arg
*darg
= impl
->decl
->args
->args
[i
];
628 if (darg
->let
&& darg
->let
->mem
) {
629 decl_type
*type
= real_decl_type(darg
->type
);
631 if (type
->type
== PSI_T_STRUCT
) {
632 size_t eos
= decl_struct_size(type
->strct
);
633 void **ptr
= (void **) ((char *) darg
->let
->mem
+ eos
);
639 efree(darg
->let
->mem
);
640 darg
->let
->mem
= NULL
;
645 PHP_MINIT_FUNCTION(psi
)
649 REGISTER_INI_ENTRIES();
651 if (!strcasecmp(PSI_G(engine
), "jit")) {
657 PSI_ContextInit(&PSI_G(context
), ops
, psi_error
);
658 PSI_ContextBuild(&PSI_G(context
), PSI_G(directory
));
662 PHP_MSHUTDOWN_FUNCTION(psi
)
664 PSI_ContextDtor(&PSI_G(context
));
666 UNREGISTER_INI_ENTRIES();
671 /* Remove if there's nothing to do at request start */
672 /* {{{ PHP_RINIT_FUNCTION
674 PHP_RINIT_FUNCTION(psi
)
676 #if defined(COMPILE_DL_PSI) && defined(ZTS)
677 ZEND_TSRMLS_CACHE_UPDATE();
683 /* Remove if there's nothing to do at request end */
684 /* {{{ PHP_RSHUTDOWN_FUNCTION
686 PHP_RSHUTDOWN_FUNCTION(psi
)
692 PHP_MINFO_FUNCTION(psi
)
694 php_info_print_table_start();
695 php_info_print_table_header(2, "psi support", "enabled");
696 php_info_print_table_end();
698 DISPLAY_INI_ENTRIES();
700 const zend_function_entry psi_functions
[] = {
704 zend_module_entry psi_module_entry
= {
705 STANDARD_MODULE_HEADER
,
710 PHP_RINIT(psi
), /* Replace with NULL if there's nothing to do at request start */
711 PHP_RSHUTDOWN(psi
), /* Replace with NULL if there's nothing to do at request end */
714 STANDARD_MODULE_PROPERTIES
717 #ifdef COMPILE_DL_PSI
719 ZEND_TSRMLS_CACHE_DEFINE();
729 * vim600: noet sw=4 ts=4 fdm=marker
730 * vim<600: noet sw=4 ts=4