8 #include "zend_exceptions.h"
14 size_t psi_t_alignment(token_t t
)
16 #define PSI_ALIGNOF(T) case PSI_T_## T: return ALIGNOF_## T ##_T;
29 return ALIGNOF_DOUBLE
;
31 return ALIGNOF_VOID_P
;
32 EMPTY_SWITCH_DEFAULT_CASE();
37 size_t psi_t_size(token_t t
)
39 #define PSI_SIZEOF(T) case PSI_T_## T : return SIZEOF_## T ##_T;
55 EMPTY_SWITCH_DEFAULT_CASE();
60 size_t psi_t_align(token_t t
, size_t s
)
62 size_t a
= psi_t_alignment(t
);
63 return ((s
- 1) | (a
- 1)) + 1;
66 size_t psi_offset_padding(size_t diff
, size_t alignment
)
68 if (diff
&& diff
<= ((diff
- 1) | (alignment
-1)) + 1) {
75 int psi_internal_type(impl_type
*type
)
94 zend_internal_arg_info
*psi_internal_arginfo(impl
*impl
)
97 zend_internal_arg_info
*aip
;
98 zend_internal_function_info
*fi
;
100 aip
= calloc(impl
->func
->args
->count
+ 1 + !!impl
->func
->args
->vararg
.name
, sizeof(*aip
));
102 fi
= (zend_internal_function_info
*) &aip
[0];
104 fi
->required_num_args
= psi_num_min_args(impl
);
105 fi
->return_reference
= impl
->func
->return_reference
;
106 fi
->type_hint
= psi_internal_type(impl
->func
->return_type
);
108 if (impl
->func
->args
->vararg
.name
) {
109 impl_arg
*vararg
= impl
->func
->args
->vararg
.name
;
110 zend_internal_arg_info
*ai
= &aip
[impl
->func
->args
->count
];
112 ai
->name
= vararg
->var
->name
;
114 ai
->type_hint
= psi_internal_type(vararg
->type
);
115 if (vararg
->var
->reference
) {
116 ai
->pass_by_reference
= 1;
121 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
122 impl_arg
*iarg
= impl
->func
->args
->args
[i
];
123 zend_internal_arg_info
*ai
= &aip
[i
+1];
125 ai
->name
= iarg
->var
->name
;
126 ai
->type_hint
= psi_internal_type(iarg
->type
);
127 if (iarg
->var
->reference
) {
128 ai
->pass_by_reference
= 1;
130 //if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
138 size_t psi_num_min_args(impl
*impl
)
140 size_t i
, n
= impl
->func
->args
->count
;
142 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
143 if (impl
->func
->args
->args
[i
]->def
) {
151 static inline ZEND_RESULT_CODE
psi_parse_args(zend_execute_data
*execute_data
, impl
*impl
)
155 zend_error_handling zeh
;
157 zend_replace_error_handling(EH_THROW
, zend_exception_get_default(), &zeh
);
159 if (!impl
->func
->args
->count
) {
162 rv
= zend_parse_parameters_none();
163 zend_restore_error_handling(&zeh
);
167 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl
), impl
->func
->args
->vararg
.name
? -1 : impl
->func
->args
->count
)
169 if (impl
->func
->args
->vararg
.name
&& _i
>= impl
->func
->args
->count
) {
170 impl_arg
*varg
= impl
->func
->args
->vararg
.name
;
171 iarg
= init_impl_arg(
172 init_impl_type(varg
->type
->type
, varg
->type
->name
),
173 init_impl_var(varg
->var
->name
, varg
->var
->reference
),
177 if (_i
== impl
->func
->args
->count
) {
178 impl
->func
->args
->vararg
.args
= init_impl_args(iarg
);
180 add_impl_arg(impl
->func
->args
->vararg
.args
, iarg
);
183 iarg
= impl
->func
->args
->args
[_i
];
188 if (PSI_T_BOOL
== iarg
->type
->type
) {
189 Z_PARAM_BOOL(iarg
->val
.zend
.bval
);
190 } else if (PSI_T_INT
== iarg
->type
->type
) {
191 Z_PARAM_LONG(iarg
->val
.zend
.lval
);
192 } else if (PSI_T_FLOAT
== iarg
->type
->type
|| PSI_T_DOUBLE
== iarg
->type
->type
) {
193 Z_PARAM_DOUBLE(iarg
->val
.dval
);
194 } else if (PSI_T_STRING
== iarg
->type
->type
) {
195 Z_PARAM_STR_EX(iarg
->val
.zend
.str
, 1, iarg
->var
->reference
);
196 if (iarg
->val
.zend
.str
) {
197 zend_string_addref(iarg
->val
.zend
.str
);
199 } else if (PSI_T_ARRAY
== iarg
->type
->type
) {
201 } else if (PSI_T_OBJECT
== iarg
->type
->type
) {
203 } else if (PSI_T_MIXED
== iarg
->type
->type
) {
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_val(token_t let_func
, impl_arg
*iarg
, impl_val
*arg_val
, decl_struct
*strct
, void **to_free
)
262 if (iarg
->type
->type
== PSI_T_BOOL
) {
263 arg_val
->cval
= iarg
->val
.zend
.bval
;
265 arg_val
->cval
= zend_is_true(iarg
->_zv
);
269 if (iarg
->type
->type
== PSI_T_INT
) {
270 arg_val
->lval
= iarg
->val
.zend
.lval
;
272 arg_val
->lval
= zval_get_long(iarg
->_zv
);
276 if (iarg
->type
->type
== PSI_T_FLOAT
|| iarg
->type
->type
== PSI_T_DOUBLE
) {
277 arg_val
->dval
= iarg
->val
.dval
;
279 arg_val
->dval
= zval_get_double(iarg
->_zv
);
284 if (iarg
->type
->type
== PSI_T_STRING
) {
285 if (iarg
->val
.zend
.str
) {
286 arg_val
->ptr
= estrndup(iarg
->val
.zend
.str
->val
, iarg
->val
.zend
.str
->len
);
287 *to_free
= arg_val
->ptr
;
292 zend_string
*zs
= zval_get_string(iarg
->_zv
);
293 arg_val
->ptr
= estrdup(zs
->val
);
294 *to_free
= arg_val
->ptr
;
295 zend_string_release(zs
);
297 if (PSI_T_PATHVAL
== let_func
) {
298 if (SUCCESS
!= php_check_open_basedir(arg_val
->ptr
)) {
305 if (iarg
->type
->type
== PSI_T_STRING
) {
306 if (iarg
->val
.zend
.str
) {
307 arg_val
->lval
= iarg
->val
.zend
.str
->len
;
312 zend_string
*zs
= zval_get_string(iarg
->_zv
);
313 arg_val
->lval
= zs
->len
;
314 zend_string_release(zs
);
318 if (iarg
->type
->type
== PSI_T_ARRAY
) {
319 arg_val
= psi_array_to_struct(strct
, HASH_OF(iarg
->_zv
));
324 if (iarg
->type
->type
== PSI_T_OBJECT
) {
327 if (!instanceof_function(Z_OBJCE_P(iarg
->_zv
), psi_object_get_class_entry())) {
331 obj
= PSI_OBJ(iarg
->_zv
, NULL
);
332 arg_val
->ptr
= obj
->data
;
335 EMPTY_SWITCH_DEFAULT_CASE();
340 static inline void *psi_do_let(let_stmt
*let
)
342 decl_arg
*darg
= let
->var
->arg
;
343 impl_val
*arg_val
= darg
->ptr
;
346 switch (let
->val
? let
->val
->kind
: PSI_LET_NULL
) {
348 memcpy(arg_val
, deref_impl_val(let
->val
->data
.var
->arg
->let
->ptr
, let
->val
->data
.var
), sizeof(*arg_val
));
350 fprintf(stderr
, "LET TMP: %p -> %p\n",
351 let
->val
->data
.var
->arg
->let
->ptr
,
356 if (darg
->var
->array_size
) {
357 arg_val
->ptr
= ecalloc(darg
->var
->array_size
, sizeof(*arg_val
));
358 darg
->mem
= arg_val
->ptr
;
360 memset(arg_val
, 0, sizeof(*arg_val
));
364 arg_val
->ptr
= psi_do_calloc(let
->val
->data
.alloc
);
365 darg
->mem
= arg_val
->ptr
;
368 arg_val
->zend
.lval
= psi_long_num_exp(let
->val
->data
.num
, NULL
);
371 iarg
= let
->val
->data
.func
->arg
;
373 if (!(darg
->ptr
= psi_let_val(let
->val
->data
.func
->type
, iarg
, darg
->ptr
, real_decl_type(darg
->type
)->strct
, &darg
->mem
))) {
378 if (let
->val
&& let
->val
->flags
.one
.is_reference
) {
379 return let
->ptr
= &darg
->ptr
;
381 return let
->ptr
= darg
->ptr
;
385 static inline void psi_do_set(zval
*return_value
, set_value
*set
)
387 decl_arg
*set_arg
= set
->vars
->vars
[0]->arg
;
389 zval_dtor(return_value
);
390 set
->func
->handler(return_value
, set
, set_arg
->let
? set_arg
->let
->ptr
: set_arg
->ptr
);
393 static inline void psi_do_return(zval
*return_value
, return_stmt
*ret
)
395 ret
->set
->func
->handler(return_value
, ret
->set
, ret
->set
->vars
->vars
[0]->arg
->ptr
);
398 static inline void psi_do_free(free_stmt
*fre
)
402 for (i
= 0; i
< fre
->calls
->count
; ++i
) {
403 free_call
*f
= fre
->calls
->list
[i
];
405 for (j
= 0; j
< f
->vars
->count
; ++j
) {
406 decl_var
*dvar
= f
->vars
->vars
[j
];
407 decl_arg
*darg
= dvar
->arg
;
408 impl_val
*fval
= darg
->let
? darg
->let
->ptr
: darg
->ptr
;
410 f
->decl
->call
.args
[j
] = deref_impl_val(fval
, dvar
);
413 /* FIXME: check in validate_* that free functions return scalar */
414 PSI_ContextCall(&PSI_G(context
), &f
->decl
->call
, NULL
);
418 static inline void psi_clean_array_struct(decl_arg
*darg
) {
420 && darg
->let
->val
->kind
== PSI_LET_FUNC
421 && darg
->let
->val
->data
.func
->type
== PSI_T_ARRVAL
) {
422 decl_type
*type
= real_decl_type(darg
->type
);
424 if (type
->type
== PSI_T_STRUCT
) {
425 void **ptr
= (void **) ((char *) darg
->mem
+ type
->strct
->size
);
434 static inline void psi_do_clean(impl
*impl
)
438 if (impl
->decl
->func
->ptr
!= &impl
->decl
->func
->val
) {
439 efree(impl
->decl
->func
->ptr
);
440 impl
->decl
->func
->ptr
= &impl
->decl
->func
->val
;
442 for (i
= 0; i
< impl
->func
->args
->count
; ++i
) {
443 impl_arg
*iarg
= impl
->func
->args
->args
[i
];
445 switch (iarg
->type
->type
) {
447 if (iarg
->val
.zend
.str
) {
448 zend_string_release(iarg
->val
.zend
.str
);
454 if (impl
->decl
->args
) for (i
= 0; i
< impl
->decl
->args
->count
; ++i
) {
455 decl_arg
*darg
= impl
->decl
->args
->args
[i
];
458 psi_clean_array_struct(darg
);
462 darg
->ptr
= &darg
->val
;
465 if (impl
->func
->args
->vararg
.args
) {
466 free_impl_args(impl
->func
->args
->vararg
.args
);
467 impl
->func
->args
->vararg
.args
= NULL
;
469 if (impl
->func
->args
->vararg
.types
) {
470 efree(impl
->func
->args
->vararg
.types
);
471 impl
->func
->args
->vararg
.types
= NULL
;
473 if (impl
->func
->args
->vararg
.values
) {
474 efree(impl
->func
->args
->vararg
.values
);
475 impl
->func
->args
->vararg
.values
= NULL
;
477 if (impl
->func
->args
->vararg
.free_list
) {
478 void **list
= impl
->func
->args
->vararg
.free_list
;
484 efree(impl
->func
->args
->vararg
.free_list
);
485 impl
->func
->args
->vararg
.free_list
= NULL
;
490 static inline void psi_do_args(impl
*impl
) {
493 for (i
= 0; i
< impl
->decl
->args
->count
; ++i
) {
494 impl
->decl
->call
.args
[i
] = impl
->decl
->args
->args
[i
]->let
->ptr
;
497 if (!impl
->decl
->func
->var
->pointer_level
) {
498 decl_type
*real
= real_decl_type(impl
->decl
->func
->type
);
500 switch (real
->type
) {
502 impl
->decl
->func
->ptr
= psi_array_to_struct(real
->strct
, NULL
);
508 static inline impl_vararg
*psi_do_varargs(impl
*impl
) {
510 impl_vararg
*va
= &impl
->func
->args
->vararg
;
511 size_t vacount
= va
->args
->count
;
518 va
->types
= ecalloc(vacount
, sizeof(*va
->types
));
519 va
->values
= ecalloc(vacount
, sizeof(*va
->values
));
521 for (i
= 0, j
= 0; i
< vacount
; ++i
) {
522 impl_arg
*vaarg
= va
->args
->args
[i
];
523 void *to_free
= NULL
;
524 token_t let_fn
, vatype
= va
->name
->type
->type
;
526 if (vatype
== PSI_T_MIXED
) {
527 switch (Z_TYPE_P(vaarg
->_zv
)) {
529 case IS_FALSE
: vatype
= PSI_T_BOOL
; break;
530 case IS_LONG
: vatype
= PSI_T_INT
; break;
531 case IS_DOUBLE
: vatype
= PSI_T_FLOAT
; break;
532 default: vatype
= PSI_T_STRING
; break;
538 case PSI_T_BOOL
: let_fn
= PSI_T_BOOLVAL
; break;
539 case PSI_T_INT
: let_fn
= PSI_T_INTVAL
; break;
541 case PSI_T_DOUBLE
: let_fn
= PSI_T_FLOATVAL
;break;
542 case PSI_T_STRING
: let_fn
= PSI_T_STRVAL
; break;
543 EMPTY_SWITCH_DEFAULT_CASE();
546 va
->types
[i
] = vatype
;
547 /* FIXME: varargs with struct-by-value :) */
548 if (!psi_let_val(let_fn
, vaarg
, &va
->values
[i
], NULL
, &to_free
)) {
553 if (!va
->free_list
) {
554 va
->free_list
= ecalloc(vacount
- i
+ 1, sizeof(*va
->free_list
));
556 va
->free_list
[j
++] = to_free
;
563 void psi_call(zend_execute_data
*execute_data
, zval
*return_value
, impl
*impl
)
566 impl_vararg
*va
= NULL
;
568 memset(impl
->decl
->func
->ptr
, 0, sizeof(impl_val
));
570 if (SUCCESS
!= psi_parse_args(execute_data
, impl
)) {
574 for (i
= 0; i
< impl
->stmts
->let
.count
; ++i
) {
575 let_stmt
*let
= impl
->stmts
->let
.list
[i
];
577 if (!psi_do_let(let
)) {
578 psi_do_return(return_value
, impl
->stmts
->ret
.list
[0]);
584 if (impl
->decl
->args
) {
587 if (impl
->func
->args
->vararg
.args
) {
588 va
= psi_do_varargs(impl
);
592 PSI_ContextCall(&PSI_G(context
), &impl
->decl
->call
, va
);
593 psi_do_return(return_value
, impl
->stmts
->ret
.list
[0]);
595 for (i
= 0; i
< impl
->stmts
->set
.count
; ++i
) {
596 set_stmt
*set
= impl
->stmts
->set
.list
[i
];
599 psi_do_set(set
->arg
->_zv
, set
->val
);
603 for (i
= 0; i
< impl
->stmts
->fre
.count
; ++i
) {
604 free_stmt
*fre
= impl
->stmts
->fre
.list
[i
];