8 #include "zend_exceptions.h"
15 size_t psi_t_alignment(token_t t
)
17 #define PSI_ALIGNOF(T) case PSI_T_## T: return ALIGNOF_## T ##_T;
30 return ALIGNOF_DOUBLE
;
33 return ALIGNOF_VOID_P
;
36 EMPTY_SWITCH_DEFAULT_CASE();
41 size_t psi_t_size(token_t t
)
43 #define PSI_SIZEOF(T) case PSI_T_## T : return SIZEOF_## T ##_T;
62 EMPTY_SWITCH_DEFAULT_CASE();
67 int psi_internal_type(impl_type
*type
)
86 zend_internal_arg_info
*psi_internal_arginfo(impl
*impl
)
89 zend_internal_arg_info
*aip
;
90 zend_internal_function_info
*fi
;
92 aip
= calloc(impl
->func
->args
->count
+ 1 + !!impl
->func
->args
->vararg
.name
, sizeof(*aip
));
94 fi
= (zend_internal_function_info
*) &aip
[0];
96 fi
->required_num_args
= psi_num_min_args(impl
);
97 fi
->return_reference
= impl
->func
->return_reference
;
98 fi
->type_hint
= psi_internal_type(impl
->func
->return_type
);
100 if (impl
->func
->args
->vararg
.name
) {
101 impl_arg
*vararg
= impl
->func
->args
->vararg
.name
;
102 zend_internal_arg_info
*ai
= &aip
[impl
->func
->args
->count
];
104 ai
->name
= vararg
->var
->name
;
106 ai
->type_hint
= psi_internal_type(vararg
->type
);
107 if (vararg
->var
->reference
) {
108 ai
->pass_by_reference
= 1;
113 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
114 impl_arg
*iarg
= impl
->func
->args
->args
[i
];
115 zend_internal_arg_info
*ai
= &aip
[i
+1];
117 ai
->name
= iarg
->var
->name
;
118 ai
->type_hint
= psi_internal_type(iarg
->type
);
119 if (iarg
->var
->reference
) {
120 ai
->pass_by_reference
= 1;
122 //if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
130 size_t psi_num_min_args(impl
*impl
)
132 size_t i
, n
= impl
->func
->args
->count
;
134 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
135 if (impl
->func
->args
->args
[i
]->def
) {
143 static inline ZEND_RESULT_CODE
psi_parse_args(zend_execute_data
*execute_data
, impl
*impl
)
147 zend_error_handling zeh
;
149 zend_replace_error_handling(EH_THROW
, zend_exception_get_default(), &zeh
);
151 if (!impl
->func
->args
->count
) {
154 rv
= zend_parse_parameters_none();
155 zend_restore_error_handling(&zeh
);
159 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl
), impl
->func
->args
->vararg
.name
? -1 : impl
->func
->args
->count
)
161 if (impl
->func
->args
->vararg
.name
&& _i
>= impl
->func
->args
->count
) {
162 impl_arg
*varg
= impl
->func
->args
->vararg
.name
;
163 iarg
= init_impl_arg(
164 init_impl_type(varg
->type
->type
, varg
->type
->name
),
165 init_impl_var(varg
->var
->name
, varg
->var
->reference
),
169 if (_i
== impl
->func
->args
->count
) {
170 impl
->func
->args
->vararg
.args
= init_impl_args(iarg
);
172 add_impl_arg(impl
->func
->args
->vararg
.args
, iarg
);
175 iarg
= impl
->func
->args
->args
[_i
];
180 if (PSI_T_BOOL
== iarg
->type
->type
) {
181 Z_PARAM_BOOL(iarg
->val
.zend
.bval
);
182 } else if (PSI_T_INT
== iarg
->type
->type
) {
183 Z_PARAM_LONG(iarg
->val
.zend
.lval
);
184 } else if (PSI_T_FLOAT
== iarg
->type
->type
|| PSI_T_DOUBLE
== iarg
->type
->type
) {
185 Z_PARAM_DOUBLE(iarg
->val
.dval
);
186 } else if (PSI_T_STRING
== iarg
->type
->type
) {
187 Z_PARAM_STR_EX(iarg
->val
.zend
.str
, 1, iarg
->var
->reference
);
188 if (iarg
->val
.zend
.str
) {
189 zend_string_addref(iarg
->val
.zend
.str
);
191 } else if (PSI_T_ARRAY
== iarg
->type
->type
) {
193 } else if (PSI_T_OBJECT
== iarg
->type
->type
) {
195 } else if (PSI_T_MIXED
== iarg
->type
->type
) {
197 } else if (PSI_T_CALLABLE
== iarg
->type
->type
) {
199 zend_fcall_info_cache fcc
;
201 Z_PARAM_FUNC_EX(fci
, fcc
, 1, 0);
204 iarg
->val
.zend
.cb
= ecalloc(1, sizeof(zend_fcall
));
205 iarg
->val
.zend
.cb
->fci
= fci
;
206 iarg
->val
.zend
.cb
->fcc
= fcc
;
209 error_code
= ZPP_ERROR_FAILURE
;
213 ZVAL_DEREF(iarg
->_zv
);
214 if (_i
< _num_args
) {
217 ZEND_PARSE_PARAMETERS_END_EX(
218 zend_restore_error_handling(&zeh
);
222 /* set up defaults */
223 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
224 if (i
>= EX_NUM_ARGS() && iarg
->def
) {
225 iarg
= impl
->func
->args
->args
[i
];
227 switch (iarg
->type
->type
) {
229 iarg
->val
.zend
.bval
= iarg
->def
->type
== PSI_T_TRUE
? 1 : 0;
232 iarg
->val
.zend
.lval
= zend_atol(iarg
->def
->text
, strlen(iarg
->def
->text
));
236 iarg
->val
.dval
= zend_strtod(iarg
->def
->text
, NULL
);
240 iarg
->val
.zend
.str
= zend_string_init(&iarg
->def
->text
[1], strlen(iarg
->def
->text
) - 2, 0);
246 zend_restore_error_handling(&zeh
);
250 static inline void *psi_do_calloc(let_calloc
*alloc
)
252 zend_long n
= psi_long_num_exp(alloc
->nmemb
, NULL
), s
= psi_long_num_exp(alloc
->size
, NULL
);
253 void *mem
= safe_emalloc(n
, s
, sizeof(void *));
254 memset(mem
, 0, n
* s
+ sizeof(void *));
256 fprintf(stderr
, "calloc: %p\n", mem
);
261 static inline impl_val
*psi_let_val(token_t let_func
, impl_arg
*iarg
, impl_val
*arg_val
, decl_struct
*strct
, void **to_free
)
267 static inline impl_val
*psi_let_func(let_func
*func
, decl_arg
*darg
) {
268 return darg
->ptr
= func
->handler(darg
->ptr
, darg
->type
, func
->var
->arg
, &darg
->mem
);
271 static inline void *psi_do_let(let_stmt
*let
)
273 decl_arg
*darg
= let
->var
->arg
;
275 switch (let
->val
? let
->val
->kind
: PSI_LET_NULL
) {
277 memcpy(darg
->ptr
, deref_impl_val(let
->val
->data
.var
->arg
->let
, let
->val
->data
.var
), sizeof(impl_val
));
280 if (darg
->var
->array_size
) {
281 darg
->val
.ptr
= ecalloc(darg
->var
->array_size
, sizeof(impl_val
));
282 darg
->mem
= darg
->val
.ptr
;
284 memset(&darg
->val
, 0, sizeof(impl_val
));
288 darg
->val
.ptr
= psi_do_calloc(let
->val
->data
.alloc
);
289 darg
->mem
= darg
->val
.ptr
;
291 case PSI_LET_CALLBACK
:
292 darg
->val
.ptr
= let
->val
->data
.callback
->decl
->call
.sym
;
295 darg
->val
.zend
.lval
= psi_long_num_exp(let
->val
->data
.num
, NULL
);
298 if (!psi_let_func(let
->val
->data
.func
, darg
)) {
304 if (let
->val
&& let
->val
->flags
.one
.is_reference
) {
305 return darg
->let
= &darg
->ptr
;
307 return darg
->let
= darg
->ptr
;
311 static inline void psi_do_return(zval
*return_value
, return_stmt
*ret
)
313 ret
->set
->func
->handler(return_value
, ret
->set
, ret
->set
->vars
->vars
[0]->arg
->ptr
);
316 static inline void psi_do_free(free_stmt
*fre
)
320 for (i
= 0; i
< fre
->calls
->count
; ++i
) {
321 free_call
*f
= fre
->calls
->list
[i
];
323 for (j
= 0; j
< f
->vars
->count
; ++j
) {
324 decl_var
*dvar
= f
->vars
->vars
[j
];
325 decl_arg
*darg
= dvar
->arg
;
326 impl_val
*fval
= darg
->let
;
328 f
->decl
->call
.args
[j
] = deref_impl_val(fval
, dvar
);
331 /* FIXME: check in validate_* that free functions return scalar */
332 PSI_ContextCall(&PSI_G(context
), &f
->decl
->call
, NULL
);
336 static inline void psi_clean_array_struct(let_stmt
*let
, decl_arg
*darg
) {
337 if (let
->val
->kind
== PSI_LET_FUNC
338 && let
->val
->data
.func
->type
== PSI_T_ARRVAL
) {
339 decl_type
*type
= real_decl_type(darg
->type
);
341 if (type
->type
== PSI_T_STRUCT
) {
342 void **ptr
= (void **) ((char *) darg
->mem
+ type
->strct
->size
);
351 static inline void psi_do_clean(impl
*impl
)
355 if (impl
->decl
->func
->ptr
!= &impl
->decl
->func
->val
) {
356 efree(impl
->decl
->func
->ptr
);
357 impl
->decl
->func
->ptr
= &impl
->decl
->func
->val
;
360 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
361 impl_arg
*iarg
= impl
->func
->args
->args
[i
];
363 switch (iarg
->type
->type
) {
365 if (iarg
->val
.zend
.str
) {
366 zend_string_release(iarg
->val
.zend
.str
);
370 if (iarg
->val
.zend
.cb
) {
371 if (iarg
->val
.zend
.cb
->fci
.size
) {
372 zend_fcall_info_args_clear(&iarg
->val
.zend
.cb
->fci
, 1);
374 efree(iarg
->val
.zend
.cb
);
380 for (i
= 0; i
< impl
->stmts
->let
.count
; ++i
) {
381 let_stmt
*let
= impl
->stmts
->let
.list
[i
];
382 decl_arg
*darg
= let
->var
->arg
;
385 psi_clean_array_struct(let
, darg
);
389 darg
->ptr
= &darg
->val
;
390 darg
->let
= darg
->ptr
;
393 if (impl
->func
->args
->vararg
.args
) {
394 free_impl_args(impl
->func
->args
->vararg
.args
);
395 impl
->func
->args
->vararg
.args
= NULL
;
397 if (impl
->func
->args
->vararg
.types
) {
398 efree(impl
->func
->args
->vararg
.types
);
399 impl
->func
->args
->vararg
.types
= NULL
;
401 if (impl
->func
->args
->vararg
.values
) {
402 efree(impl
->func
->args
->vararg
.values
);
403 impl
->func
->args
->vararg
.values
= NULL
;
405 if (impl
->func
->args
->vararg
.free_list
) {
406 void **list
= impl
->func
->args
->vararg
.free_list
;
412 efree(impl
->func
->args
->vararg
.free_list
);
413 impl
->func
->args
->vararg
.free_list
= NULL
;
418 static inline void psi_do_args(impl
*impl
) {
421 for (i
= 0; i
< impl
->decl
->args
->count
; ++i
) {
422 impl
->decl
->call
.args
[i
] = impl
->decl
->args
->args
[i
]->let
;
425 if (!impl
->decl
->func
->var
->pointer_level
) {
426 decl_type
*real
= real_decl_type(impl
->decl
->func
->type
);
428 switch (real
->type
) {
430 impl
->decl
->func
->ptr
= psi_array_to_struct(real
->strct
, NULL
);
436 static inline impl_vararg
*psi_do_varargs(impl
*impl
) {
438 impl_vararg
*va
= &impl
->func
->args
->vararg
;
439 size_t vacount
= va
->args
->count
;
446 va
->types
= ecalloc(vacount
, sizeof(*va
->types
));
447 va
->values
= ecalloc(vacount
, sizeof(*va
->values
));
449 for (i
= 0, j
= 0; i
< vacount
; ++i
) {
450 impl_arg
*vaarg
= va
->args
->args
[i
];
451 void *to_free
= NULL
;
452 token_t vatype
= va
->name
->type
->type
;
453 let_func_handler let_fn
;
455 if (vatype
== PSI_T_MIXED
) {
456 switch (Z_TYPE_P(vaarg
->_zv
)) {
458 case IS_FALSE
: vatype
= PSI_T_BOOL
; break;
459 case IS_LONG
: vatype
= PSI_T_INT
; break;
460 case IS_DOUBLE
: vatype
= PSI_T_FLOAT
; break;
461 default: vatype
= PSI_T_STRING
; break;
467 case PSI_T_BOOL
: let_fn
= psi_let_boolval
; break;
468 case PSI_T_INT
: let_fn
= psi_let_intval
; break;
470 case PSI_T_DOUBLE
: let_fn
= psi_let_floatval
; break;
471 case PSI_T_STRING
: let_fn
= psi_let_strval
; break;
472 EMPTY_SWITCH_DEFAULT_CASE();
475 va
->types
[i
] = vatype
;
477 /* FIXME: varargs with struct-by-value :) */
478 //if (!psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free)) {
479 if (!let_fn(&va
->values
[i
], NULL
, vaarg
, &to_free
)) {
484 if (!va
->free_list
) {
485 va
->free_list
= ecalloc(vacount
- i
+ 1, sizeof(*va
->free_list
));
487 va
->free_list
[j
++] = to_free
;
494 ZEND_RESULT_CODE
psi_call(zend_execute_data
*execute_data
, zval
*return_value
, impl
*impl
)
497 impl_vararg
*va
= NULL
;
499 memset(impl
->decl
->func
->ptr
, 0, sizeof(impl_val
));
501 if (SUCCESS
!= psi_parse_args(execute_data
, impl
)) {
505 for (i
= 0; i
< impl
->stmts
->let
.count
; ++i
) {
506 let_stmt
*let
= impl
->stmts
->let
.list
[i
];
508 if (!psi_do_let(let
)) {
509 psi_do_return(return_value
, impl
->stmts
->ret
.list
[0]);
515 if (impl
->decl
->args
) {
518 if (impl
->func
->args
->vararg
.args
) {
519 va
= psi_do_varargs(impl
);
523 PSI_ContextCall(&PSI_G(context
), &impl
->decl
->call
, va
);
524 psi_do_return(return_value
, impl
->stmts
->ret
.list
[0]);
526 for (i
= 0; i
< impl
->stmts
->set
.count
; ++i
) {
527 set_stmt
*set
= impl
->stmts
->set
.list
[i
];
530 psi_do_set(set
->arg
->_zv
, set
->val
);
534 for (i
= 0; i
< impl
->stmts
->fre
.count
; ++i
) {
535 free_stmt
*fre
= impl
->stmts
->fre
.list
[i
];
544 ZEND_RESULT_CODE
psi_callback(let_callback
*cb
, void *retval
, unsigned argc
, void **argv
)
547 decl
*decl_cb
= cb
->decl
;
548 impl_arg
*iarg
= cb
->func
->var
->arg
;
549 zval return_value
, *zargv
= calloc(argc
, sizeof(*zargv
));
550 void *result
, *to_free
= NULL
;
552 ZEND_ASSERT(argc
== cb
->decl
->args
->count
);
554 /* prepare args for the userland call */
555 for (i
= 0; i
< argc
; ++i
) {
556 cb
->decl
->args
->args
[i
]->let
= argv
[i
];
558 for (i
= 0; i
< cb
->args
->count
; ++i
) {
559 psi_do_set(&zargv
[i
], cb
->args
->vals
[i
]);
561 zend_fcall_info_argp(&iarg
->val
.zend
.cb
->fci
, cb
->args
->count
, zargv
);
563 /* callback into userland */
564 ZVAL_UNDEF(&return_value
);
565 iarg
->_zv
= &return_value
;
566 zend_fcall_info_call(&iarg
->val
.zend
.cb
->fci
, &iarg
->val
.zend
.cb
->fcc
, iarg
->_zv
, NULL
);
568 /* marshal return value of the userland call */
569 switch (iarg
->type
->type
) {
570 case PSI_T_BOOL
: zend_parse_arg_bool(iarg
->_zv
, &iarg
->val
.zend
.bval
, NULL
, 0); break;
571 case PSI_T_LONG
: zend_parse_arg_long(iarg
->_zv
, &iarg
->val
.zend
.lval
, NULL
, 0, 1); break;
573 case PSI_T_DOUBLE
: zend_parse_arg_double(iarg
->_zv
, &iarg
->val
.dval
, NULL
, 0); break;
574 case PSI_T_STRING
: zend_parse_arg_str(iarg
->_zv
, &iarg
->val
.zend
.str
, 0); break;
576 result
= cb
->func
->handler(retval
, decl_cb
->func
->type
, iarg
, &to_free
);
578 if (result
!= retval
) {
579 *(void **)retval
= result
;
582 zend_fcall_info_args_clear(&iarg
->val
.zend
.cb
->fci
, 0);
583 for (i
= 0; i
< cb
->args
->count
; ++i
) {
584 zval_ptr_dtor(&zargv
[i
]);