4 # include "php_config.h"
10 #include "zend_exceptions.h"
11 #include "zend_interfaces.h"
12 #include "ext/spl/spl_iterators.h"
19 static inline void psi_do_set(zval
*return_value
, set_value
*set
)
21 decl_arg
*set_arg
= set
->vars
->vars
[0]->arg
;
23 zval_dtor(return_value
);
24 set
->func
->handler(return_value
, set
, set_arg
->let
);
27 int psi_internal_type(impl_type
*type
)
46 zend_long
psi_zval_count(zval
*zvalue
)
48 /* mimic PHP count() */
52 switch (Z_TYPE_P(zvalue
)) {
60 count
= zend_array_count(Z_ARRVAL_P(zvalue
));
64 if (Z_OBJ_HT_P(zvalue
)->count_elements
) {
65 if (SUCCESS
== Z_OBJ_HT_P(zvalue
)->count_elements(zvalue
, &count
)) {
70 if (instanceof_function(Z_OBJCE_P(zvalue
), spl_ce_Countable
)) {
71 zend_call_method_with_0_params(zvalue
, NULL
, NULL
, "count", &retval
);
72 if (Z_TYPE(retval
) != IS_UNDEF
) {
73 count
= zval_get_long(&retval
);
74 zval_ptr_dtor(&retval
);
83 zend_internal_arg_info
*psi_internal_arginfo(impl
*impl
)
86 zend_internal_arg_info
*aip
;
87 zend_internal_function_info
*fi
;
89 aip
= calloc(impl
->func
->args
->count
+ 1 + !!impl
->func
->args
->vararg
.name
, sizeof(*aip
));
91 fi
= (zend_internal_function_info
*) &aip
[0];
93 fi
->required_num_args
= psi_num_min_args(impl
);
94 fi
->return_reference
= impl
->func
->return_reference
;
95 fi
->type_hint
= psi_internal_type(impl
->func
->return_type
);
97 if (impl
->func
->args
->vararg
.name
) {
98 impl_arg
*vararg
= impl
->func
->args
->vararg
.name
;
99 zend_internal_arg_info
*ai
= &aip
[impl
->func
->args
->count
];
101 ai
->name
= vararg
->var
->name
;
103 ai
->type_hint
= psi_internal_type(vararg
->type
);
104 if (vararg
->var
->reference
) {
105 ai
->pass_by_reference
= 1;
110 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
111 impl_arg
*iarg
= impl
->func
->args
->args
[i
];
112 zend_internal_arg_info
*ai
= &aip
[i
+1];
114 ai
->name
= iarg
->var
->name
;
115 ai
->type_hint
= psi_internal_type(iarg
->type
);
116 if (iarg
->var
->reference
) {
117 ai
->pass_by_reference
= 1;
119 //if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
127 size_t psi_num_min_args(impl
*impl
)
129 size_t i
, n
= impl
->func
->args
->count
;
131 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
132 if (impl
->func
->args
->args
[i
]->def
) {
140 static inline ZEND_RESULT_CODE
psi_parse_args(zend_execute_data
*execute_data
, impl
*impl
)
144 zend_error_handling zeh
;
146 zend_replace_error_handling(EH_THROW
, zend_exception_get_default(), &zeh
);
148 if (!impl
->func
->args
->count
) {
151 rv
= zend_parse_parameters_none();
152 zend_restore_error_handling(&zeh
);
156 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl
), impl
->func
->args
->vararg
.name
? -1 : impl
->func
->args
->count
)
158 if (impl
->func
->args
->vararg
.name
&& _i
>= impl
->func
->args
->count
) {
159 impl_arg
*varg
= impl
->func
->args
->vararg
.name
;
160 iarg
= init_impl_arg(
161 init_impl_type(varg
->type
->type
, varg
->type
->name
),
162 init_impl_var(varg
->var
->name
, varg
->var
->reference
),
166 if (_i
== impl
->func
->args
->count
) {
167 impl
->func
->args
->vararg
.args
= init_impl_args(iarg
);
169 add_impl_arg(impl
->func
->args
->vararg
.args
, iarg
);
172 iarg
= impl
->func
->args
->args
[_i
];
177 if (PSI_T_BOOL
== iarg
->type
->type
) {
178 Z_PARAM_BOOL(iarg
->val
.zend
.bval
);
179 } else if (PSI_T_INT
== iarg
->type
->type
) {
180 Z_PARAM_LONG(iarg
->val
.zend
.lval
);
181 } else if (PSI_T_FLOAT
== iarg
->type
->type
|| PSI_T_DOUBLE
== iarg
->type
->type
) {
182 Z_PARAM_DOUBLE(iarg
->val
.dval
);
183 } else if (PSI_T_STRING
== iarg
->type
->type
) {
184 Z_PARAM_STR_EX(iarg
->val
.zend
.str
, 1, iarg
->var
->reference
);
185 if (iarg
->val
.zend
.str
) {
186 zend_string_addref(iarg
->val
.zend
.str
);
188 } else if (PSI_T_ARRAY
== iarg
->type
->type
) {
190 } else if (PSI_T_OBJECT
== iarg
->type
->type
) {
192 } else if (PSI_T_MIXED
== iarg
->type
->type
) {
194 } else if (PSI_T_CALLABLE
== iarg
->type
->type
) {
196 zend_fcall_info_cache fcc
;
198 Z_PARAM_FUNC_EX(fci
, fcc
, 1, 0);
201 iarg
->val
.zend
.cb
= ecalloc(1, sizeof(zend_fcall
));
202 iarg
->val
.zend
.cb
->fci
= fci
;
203 iarg
->val
.zend
.cb
->fcc
= fcc
;
206 error_code
= ZPP_ERROR_FAILURE
;
210 ZVAL_DEREF(iarg
->_zv
);
211 if (_i
< _num_args
) {
214 ZEND_PARSE_PARAMETERS_END_EX(
215 zend_restore_error_handling(&zeh
);
219 /* set up defaults */
220 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
221 if (i
>= EX_NUM_ARGS() && iarg
->def
) {
222 iarg
= impl
->func
->args
->args
[i
];
224 switch (iarg
->type
->type
) {
226 iarg
->val
.zend
.bval
= iarg
->def
->type
== PSI_T_TRUE
? 1 : 0;
229 iarg
->val
.zend
.lval
= zend_atol(iarg
->def
->text
, strlen(iarg
->def
->text
));
233 iarg
->val
.dval
= zend_strtod(iarg
->def
->text
, NULL
);
237 iarg
->val
.zend
.str
= zend_string_init(&iarg
->def
->text
[1], strlen(iarg
->def
->text
) - 2, 0);
243 zend_restore_error_handling(&zeh
);
247 static inline void *psi_do_calloc(let_calloc
*alloc
)
249 zend_long n
= psi_long_num_exp(alloc
->nmemb
, NULL
), s
= psi_long_num_exp(alloc
->size
, NULL
);
250 void *mem
= safe_emalloc(n
, s
, sizeof(void *));
251 memset(mem
, 0, n
* s
+ sizeof(void *));
253 fprintf(stderr
, "calloc: %p\n", mem
);
258 static inline impl_val
*psi_let_func(let_func
*func
, decl_arg
*darg
);
260 static inline void *psi_let_val(let_val
*val
, decl_arg
*darg
)
264 switch (val
? val
->kind
: PSI_LET_NULL
) {
266 memcpy(darg
->ptr
, deref_impl_val(val
->data
.var
->arg
->let
, val
->data
.var
), sizeof(impl_val
));
269 if (darg
->var
->array_size
) {
270 darg
->val
.ptr
= ecalloc(darg
->var
->array_size
, sizeof(impl_val
));
271 darg
->mem
= darg
->val
.ptr
;
273 memset(&darg
->val
, 0, sizeof(impl_val
));
277 darg
->val
.ptr
= psi_do_calloc(val
->data
.alloc
);
278 darg
->mem
= darg
->val
.ptr
;
281 darg
->val
.zend
.lval
= psi_long_num_exp(val
->data
.num
, NULL
);
283 case PSI_LET_CALLBACK
:
284 darg
->val
.ptr
= val
->data
.callback
->decl
->call
.sym
;
287 if (!psi_let_func(val
->data
.func
, darg
)) {
293 if (val
&& val
->is_reference
) {
294 return darg
->let
= &darg
->ptr
;
296 return darg
->let
= darg
->ptr
;
300 static inline impl_val
*psi_let_func_ex(let_func
*func
, void *dptr
, decl_type
*dtype
, decl_var
*dvar
, token_t itype
, impl_val
*ival
, zval
*zvalue
, void **to_free
) {
301 switch (func
->type
) {
303 return psi_let_boolval(dptr
, dtype
, itype
, ival
, zvalue
, to_free
);
305 return psi_let_intval(dptr
, dtype
, itype
, ival
, zvalue
, to_free
);
307 return psi_let_floatval(dptr
, dtype
, itype
, ival
, zvalue
, to_free
);
309 return psi_let_strval(dptr
, dtype
, itype
, ival
, zvalue
, to_free
);
311 return psi_let_strlen(dptr
, dtype
, itype
, ival
, zvalue
, to_free
);
313 return psi_let_pathval(dptr
, dtype
, itype
, ival
, zvalue
, to_free
);
315 return psi_let_objval(dptr
, dtype
, itype
, ival
, zvalue
, to_free
);
317 return psi_let_zval(dptr
, dtype
, itype
, ival
, zvalue
, to_free
);
319 return psi_let_void(dptr
, dtype
, itype
, ival
, zvalue
, to_free
);
321 return psi_let_count(dptr
, dtype
, itype
, ival
, zvalue
, to_free
);
327 decl_args
*args
= extract_decl_type_args(dtype
, &real
);
329 if (itype
!= PSI_T_ARRAY
) {
330 SEPARATE_ARG_IF_REF(zvalue
);
331 convert_to_array(zvalue
);
335 size_t size
= extract_decl_type_size(real
, NULL
);
337 mem
= ecalloc(1, size
+ args
->count
* sizeof(void *));
339 for (i
= 0; i
< args
->count
; ++i
) {
340 decl_arg
*darg
= args
->args
[i
];
341 let_val
*lval
= locate_let_vals_val(func
->inner
, darg
->var
->name
);
342 impl_val
*ptr
= NULL
;
345 if ((ptr
= psi_let_val(lval
, darg
))) {
346 memcpy(mem
+ darg
->layout
->pos
, ptr
, darg
->layout
->len
);
348 ((void **)(mem
+ size
))[j
++] = darg
->mem
;
351 if (real
->type
== PSI_T_UNION
) {
358 let_val
*inner
= func
->inner
->vals
[0];
363 sub_var
= inner
->var
;
365 sub_var
= copy_decl_var(dvar
);
366 assert(sub_var
->pointer_level
);
367 --sub_var
->pointer_level
;
370 size
= sub_var
->pointer_level
? SIZEOF_VOID_P
: extract_decl_type_size(real
, NULL
);
371 mem
= ecalloc(1, size
* (1 + zend_array_count(Z_ARRVAL_P(zvalue
))));
373 ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(zvalue
), zv
)
376 impl_val val
= {0}, *ptr
, *sub
;
378 ptr
= psi_let_func_ex(inner
->data
.func
, &val
, real
, dvar
, 0, NULL
, zv
, &tmp
);
379 sub
= deref_impl_val(ptr
, sub_var
);
381 memcpy(&mem
[size
* j
++], &sub
, size
);
383 ZEND_HASH_FOREACH_END();
385 if (sub_var
!= inner
->var
) {
386 free_decl_var(sub_var
);
389 return *to_free
= mem
;
391 return psi_let_arrval(dptr
, dtype
, dvar
, itype
, ival
, zvalue
, to_free
);
400 static inline impl_val
*psi_let_func(let_func
*func
, decl_arg
*darg
) {
402 if (func
->var
->arg
) {
403 return darg
->ptr
= psi_let_func_ex(func
,
404 darg
->ptr
, darg
->type
, darg
->var
,
405 func
->var
->arg
->type
->type
,
406 &func
->var
->arg
->val
,
410 impl_var
*ivar
= locate_let_val_impl_var(func
->outer
);
411 zval
*entry
= zend_symtable_str_find(Z_ARRVAL_P(ivar
->arg
->_zv
), func
->var
->name
+1, strlen(func
->var
->name
)-1);
412 impl_arg
*iarg
= init_impl_arg(
413 init_impl_type(PSI_T_MIXED
, "mixed"),
414 copy_impl_var(func
->var
), NULL
);
416 func
->var
->arg
= iarg
;
423 iarg
->_zv
= zend_symtable_str_update_ind(Z_ARRVAL_P(ivar
->arg
->_zv
), func
->var
->name
+1, strlen(func
->var
->name
)-1, &ztmp
);
426 psi_let_func(func
, darg
);
433 static inline void *psi_do_let(let_stmt
*let
)
435 return psi_let_val(let
->val
, let
->val
->var
->arg
);
438 static inline void psi_do_return(zval
*return_value
, return_stmt
*ret
)
440 ret
->set
->func
->handler(return_value
, ret
->set
, ret
->set
->vars
->vars
[0]->arg
->ptr
);
443 static inline void psi_do_free(free_stmt
*fre
)
447 for (i
= 0; i
< fre
->calls
->count
; ++i
) {
448 free_call
*f
= fre
->calls
->list
[i
];
450 for (j
= 0; j
< f
->vars
->count
; ++j
) {
451 decl_var
*dvar
= f
->vars
->vars
[j
];
452 decl_arg
*darg
= dvar
->arg
;
453 impl_val
*fval
= darg
->let
;
455 f
->decl
->call
.args
[j
] = deref_impl_val(fval
, dvar
);
458 /* FIXME: check in validate_* that free functions return scalar */
459 psi_context_call(&PSI_G(context
), &f
->decl
->call
, NULL
);
463 static inline void psi_clean_array_struct(let_val
*val
, decl_arg
*darg
) {
464 if (val
->kind
== PSI_LET_FUNC
465 && val
->data
.func
->type
== PSI_T_ARRVAL
) {
466 decl_type
*type
= real_decl_type(darg
->type
);
468 if (type
->type
== PSI_T_STRUCT
) {
469 void **ptr
= (void **) ((char *) darg
->mem
+ type
->real
.strct
->size
);
474 // args = type->real.strct->args;
475 } else if (type
->type
== PSI_T_UNION
) {
476 void **ptr
= (void **) ((char *) darg
->mem
+ type
->real
.unn
->size
);
481 // args = type->real.unn->args;
484 if (args
&& val
->data
.func
->inner
) {
487 for (i
= 0; i
< val
->data
.func
->inner
->count
; ++i
) {
488 let_val
*inner
= val
->data
.func
->inner
->vals
[i
];
489 decl_var
*refvar
= locate_let_val_inner_ref(inner
)->var
;
490 decl_arg
*subarg
= locate_decl_arg(args
, refvar
->name
);
493 psi_clean_array_struct(val
->data
.func
->inner
->vals
[i
], subarg
);
505 static inline void psi_clean_let_val(let_val
*val
) {
507 let_func
*func
= locate_let_val_func(val
);
509 if (func
&& func
->inner
) {
512 for (i
= 0; i
< func
->inner
->count
; ++i
) {
513 let_val
*inner
= func
->inner
->vals
[i
];
514 psi_clean_let_val(inner
);
518 decl_arg
*darg
= val
->var
->arg
;
521 psi_clean_array_struct(val
, darg
);
525 darg
->ptr
= &darg
->val
;
526 darg
->let
= darg
->ptr
;
531 static inline void psi_do_clean(impl
*impl
)
535 if (impl
->decl
->func
->ptr
!= &impl
->decl
->func
->val
) {
536 efree(impl
->decl
->func
->ptr
);
537 impl
->decl
->func
->ptr
= &impl
->decl
->func
->val
;
540 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
541 impl_arg
*iarg
= impl
->func
->args
->args
[i
];
543 switch (iarg
->type
->type
) {
545 if (iarg
->val
.zend
.str
) {
546 zend_string_release(iarg
->val
.zend
.str
);
550 if (iarg
->val
.zend
.cb
) {
551 if (iarg
->val
.zend
.cb
->fci
.size
) {
552 zend_fcall_info_args_clear(&iarg
->val
.zend
.cb
->fci
, 1);
554 efree(iarg
->val
.zend
.cb
);
560 for (i
= 0; i
< impl
->stmts
->let
.count
; ++i
) {
561 let_stmt
*let
= impl
->stmts
->let
.list
[i
];
562 psi_clean_let_val(let
->val
);
565 if (impl
->func
->args
->vararg
.args
) {
566 free_impl_args(impl
->func
->args
->vararg
.args
);
567 impl
->func
->args
->vararg
.args
= NULL
;
569 if (impl
->func
->args
->vararg
.types
) {
570 efree(impl
->func
->args
->vararg
.types
);
571 impl
->func
->args
->vararg
.types
= NULL
;
573 if (impl
->func
->args
->vararg
.values
) {
574 efree(impl
->func
->args
->vararg
.values
);
575 impl
->func
->args
->vararg
.values
= NULL
;
577 if (impl
->func
->args
->vararg
.free_list
) {
578 void **list
= impl
->func
->args
->vararg
.free_list
;
584 efree(impl
->func
->args
->vararg
.free_list
);
585 impl
->func
->args
->vararg
.free_list
= NULL
;
590 static inline void psi_do_args(impl
*impl
) {
593 for (i
= 0; i
< impl
->decl
->args
->count
; ++i
) {
594 impl
->decl
->call
.args
[i
] = impl
->decl
->args
->args
[i
]->let
;
597 if (!impl
->decl
->func
->var
->pointer_level
) {
599 decl_args
*args
= extract_decl_type_args(impl
->decl
->func
->type
, &real
);
601 switch (real
->type
) {
604 impl
->decl
->func
->ptr
= ecalloc(1,
605 extract_decl_type_size(real
, NULL
) + args
->count
* sizeof(void*));
613 static inline impl_vararg
*psi_do_varargs(impl
*impl
) {
615 impl_vararg
*va
= &impl
->func
->args
->vararg
;
616 size_t vacount
= va
->args
->count
;
623 va
->types
= ecalloc(vacount
, sizeof(*va
->types
));
624 va
->values
= ecalloc(vacount
, sizeof(*va
->values
));
626 for (i
= 0, j
= 0; i
< vacount
; ++i
) {
627 impl_arg
*vaarg
= va
->args
->args
[i
];
628 void *to_free
= NULL
;
629 token_t vatype
= va
->name
->type
->type
;
630 psi_marshal_let let_fn
;
632 if (vatype
== PSI_T_MIXED
) {
633 switch (Z_TYPE_P(vaarg
->_zv
)) {
635 case IS_FALSE
: vatype
= PSI_T_BOOL
; break;
636 case IS_LONG
: vatype
= PSI_T_INT
; break;
637 case IS_DOUBLE
: vatype
= PSI_T_FLOAT
; break;
638 default: vatype
= PSI_T_STRING
; break;
644 case PSI_T_BOOL
: let_fn
= psi_let_boolval
; break;
645 case PSI_T_INT
: let_fn
= psi_let_intval
; break;
647 case PSI_T_DOUBLE
: let_fn
= psi_let_floatval
; break;
648 case PSI_T_STRING
: let_fn
= psi_let_strval
; break;
649 EMPTY_SWITCH_DEFAULT_CASE();
652 va
->types
[i
] = vatype
;
654 /* FIXME: varargs with struct-by-value :) */
655 //if (!psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free)) {
656 if (!let_fn(&va
->values
[i
], NULL
, vaarg
->type
->type
, &vaarg
->val
, vaarg
->_zv
, &to_free
)) {
661 if (!va
->free_list
) {
662 va
->free_list
= ecalloc(vacount
- i
+ 1, sizeof(*va
->free_list
));
664 va
->free_list
[j
++] = to_free
;
671 ZEND_RESULT_CODE
psi_call(zend_execute_data
*execute_data
, zval
*return_value
, impl
*impl
)
674 impl_vararg
*va
= NULL
;
676 memset(impl
->decl
->func
->ptr
, 0, sizeof(impl_val
));
678 if (SUCCESS
!= psi_parse_args(execute_data
, impl
)) {
682 for (i
= 0; i
< impl
->stmts
->let
.count
; ++i
) {
683 let_stmt
*let
= impl
->stmts
->let
.list
[i
];
685 if (!psi_do_let(let
)) {
686 psi_do_return(return_value
, impl
->stmts
->ret
.list
[0]);
692 if (impl
->decl
->args
) {
695 if (impl
->func
->args
->vararg
.args
) {
696 va
= psi_do_varargs(impl
);
700 psi_context_call(&PSI_G(context
), &impl
->decl
->call
, va
);
701 psi_do_return(return_value
, impl
->stmts
->ret
.list
[0]);
703 for (i
= 0; i
< impl
->stmts
->set
.count
; ++i
) {
704 set_stmt
*set
= impl
->stmts
->set
.list
[i
];
707 psi_do_set(set
->arg
->_zv
, set
->val
);
711 for (i
= 0; i
< impl
->stmts
->fre
.count
; ++i
) {
712 free_stmt
*fre
= impl
->stmts
->fre
.list
[i
];
721 ZEND_RESULT_CODE
psi_callback(let_callback
*cb
, void *retval
, unsigned argc
, void **argv
)
724 decl
*decl_cb
= cb
->decl
;
725 impl_arg
*iarg
= cb
->func
->var
->arg
;
726 zval return_value
, *zargv
= calloc(argc
, sizeof(*zargv
));
727 void *result
, *to_free
= NULL
;
729 ZEND_ASSERT(argc
== cb
->decl
->args
->count
);
731 /* prepare args for the userland call */
732 for (i
= 0; i
< argc
; ++i
) {
733 cb
->decl
->args
->args
[i
]->let
= argv
[i
];
735 for (i
= 0; i
< cb
->args
->count
; ++i
) {
736 psi_do_set(&zargv
[i
], cb
->args
->vals
[i
]);
738 zend_fcall_info_argp(&iarg
->val
.zend
.cb
->fci
, cb
->args
->count
, zargv
);
740 /* callback into userland */
741 ZVAL_UNDEF(&return_value
);
742 iarg
->_zv
= &return_value
;
743 zend_fcall_info_call(&iarg
->val
.zend
.cb
->fci
, &iarg
->val
.zend
.cb
->fcc
, iarg
->_zv
, NULL
);
745 /* marshal return value of the userland call
746 switch (iarg->type->type) {
747 case PSI_T_BOOL: zend_parse_arg_bool(iarg->_zv, &iarg->val.zend.bval, NULL, 0); break;
748 case PSI_T_LONG: zend_parse_arg_long(iarg->_zv, &iarg->val.zend.lval, NULL, 0, 1); break;
750 case PSI_T_DOUBLE: zend_parse_arg_double(iarg->_zv, &iarg->val.dval, NULL, 0); break;
751 case PSI_T_STRING: zend_parse_arg_str(iarg->_zv, &iarg->val.zend.str, 0); break;
754 result
= psi_let_func_ex(cb
->func
, retval
, decl_cb
->func
->type
, decl_cb
->func
->var
, 0, &iarg
->val
, iarg
->_zv
, &to_free
);
755 // result = cb->func->handler(retval, decl_cb->func->type, iarg, &to_free);
757 if (result
!= retval
) {
758 *(void **)retval
= result
;
761 zend_fcall_info_args_clear(&iarg
->val
.zend
.cb
->fci
, 0);
762 for (i
= 0; i
< cb
->args
->count
; ++i
) {
763 zval_ptr_dtor(&zargv
[i
]);