1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
26 #include "php_psi_stdinc.h"
32 #include "zend_exceptions.h"
34 struct psi_call_frame_argument
*psi_call_frame_argument_init(struct psi_impl_arg
*spec
,
35 impl_val
*ival
, zval
*zptr
, int is_vararg
) {
36 struct psi_call_frame_argument
*frame_arg
= ecalloc(1, sizeof(*frame_arg
));
39 if ((frame_arg
->zval_ptr
= zptr
)) {
40 ZVAL_DEREF(frame_arg
->zval_ptr
);
42 /* use userland type if the declared type of the vararg is mixed */
44 if (spec
->type
->type
== PSI_T_MIXED
) {
45 switch (Z_TYPE_P(zptr
)) {
47 frame_arg
->va_type
= PSI_T_BOOL
;
51 frame_arg
->va_type
= PSI_T_BOOL
;
55 frame_arg
->va_type
= PSI_T_INT
;
56 ival
->zend
.lval
= Z_LVAL_P(zptr
);
59 frame_arg
->va_type
= PSI_T_FLOAT
;
60 ival
->dval
= Z_DVAL_P(zptr
);
63 frame_arg
->va_type
= PSI_T_STRING
;
64 ival
->zend
.str
= zval_get_string(zptr
);
68 frame_arg
->va_type
= spec
->type
->type
;
73 frame_arg
->ival
= *ival
;
74 frame_arg
->ival_ptr
= &frame_arg
->ival
;
75 frame_arg
->spec
= spec
;
80 void psi_call_frame_argument_free(struct psi_call_frame_argument
*arg
) {
81 switch (arg
->spec
->type
->type
) {
83 if (arg
->ival
.zend
.str
) {
84 zend_string_release(arg
->ival
.zend
.str
);
88 if (arg
->ival
.zend
.cb
) {
89 if (arg
->ival
.zend
.cb
->fci
.size
) {
90 zend_fcall_info_args_clear(&arg
->ival
.zend
.cb
->fci
, 1);
92 efree(arg
->ival
.zend
.cb
);
98 if (arg
->ival_ptr
&& arg
->ival_ptr
!= &arg
->temp_val
&& arg
->ival_ptr
!= &arg
->ival
) {
104 struct psi_call_frame_symbol
*psi_call_frame_symbol_init(struct psi_decl_var
*dvar
) {
105 struct psi_call_frame_symbol
*frame_sym
;
106 size_t size
= psi_decl_type_get_size(dvar
->arg
->type
, NULL
);
108 frame_sym
= ecalloc(1, sizeof(*frame_sym
) + size
);
109 frame_sym
->ptr
= frame_sym
->ival_ptr
= &frame_sym
->temp_val
;
114 void psi_call_frame_symbol_free(struct psi_call_frame_symbol
*sym
) {
118 static void psi_call_frame_free_argument(zval
*zptr
) {
119 psi_call_frame_argument_free(Z_PTR_P(zptr
));
122 static void psi_call_frame_free_symbol(zval
*zptr
) {
123 psi_call_frame_symbol_free(Z_PTR_P(zptr
));
126 struct psi_call_frame_auto_free
{
128 void (*dtor
)(void *);
131 static void psi_call_frame_free_temp(void *ptr
) {
132 struct psi_call_frame_auto_free
*f
= ptr
;
143 struct psi_call_frame
*psi_call_frame_init(struct psi_context
*C
, struct psi_decl
*decl
, struct psi_impl
*impl
) {
144 struct psi_call_frame
*frame
= ecalloc(1, sizeof(*frame
));
150 zend_hash_init(&frame
->arguments
, 8, NULL
, psi_call_frame_free_argument
, 0);
151 zend_hash_init(&frame
->symbols
, 8, NULL
, psi_call_frame_free_symbol
, 0);
152 zend_llist_init(&frame
->temp
, sizeof(struct psi_call_frame_auto_free
), psi_call_frame_free_temp
, 0);
157 struct psi_call_frame_symbol
*psi_call_frame_fetch_symbol(
158 struct psi_call_frame
*frame
, struct psi_decl_var
*dvar
) {
159 struct psi_call_frame_symbol
*frame_sym
;
161 frame_sym
= zend_hash_str_find_ptr(&frame
->symbols
, dvar
->fqn
, strlen(dvar
->fqn
));
163 frame_sym
= zend_hash_str_add_ptr(&frame
->symbols
, dvar
->fqn
, strlen(dvar
->fqn
),
164 psi_call_frame_symbol_init(dvar
));
169 zval
*psi_call_frame_new_argument(struct psi_call_frame
*frame
,
170 struct psi_call_frame_argument
*frame_arg
) {
171 if (frame_arg
->va_type
) {
172 /* varargs are just appended with numeric indices */
173 return zend_hash_next_index_insert_ptr(&frame
->arguments
, frame_arg
);
175 return zend_hash_str_add_ptr(&frame
->arguments
,
176 frame_arg
->spec
->var
->name
, strlen(frame_arg
->spec
->var
->name
),
181 zval
*psi_call_frame_sub_argument(struct psi_call_frame
*frame
,
182 struct psi_impl_var
*inner_var
, zval
*outer_zval
, const char *name
) {
183 struct psi_call_frame_argument
*iarg
;
184 zval
*inner_zval
= zend_symtable_str_find(Z_ARRVAL_P(outer_zval
),
185 &inner_var
->name
[1], strlen(&inner_var
->name
[1]));
190 SEPARATE_ZVAL(outer_zval
);
191 ZVAL_NULL(&empty_zval
);
192 inner_zval
= zend_symtable_str_update(Z_ARRVAL_P(outer_zval
),
193 &inner_var
->name
[1], strlen(&inner_var
->name
[1]),
197 iarg
= psi_call_frame_get_argument(frame
, name
);
200 struct psi_call_frame_argument
*frame_arg
;
201 impl_val empty_val
= {0};
202 struct psi_impl_arg
*carg_spec
= psi_impl_arg_init(
203 psi_impl_type_init(PSI_T_MIXED
, "mixed"),
204 psi_impl_var_copy(inner_var
), NULL
);
206 psi_call_frame_push_auto_ex(frame
, carg_spec
, (void(*)(void*)) psi_impl_arg_free
);
207 frame_arg
= psi_call_frame_argument_init(carg_spec
, &empty_val
, inner_zval
, 0);
208 zend_hash_str_add_ptr(&frame
->arguments
, name
, strlen(name
), frame_arg
);
214 struct psi_call_frame_argument
*psi_call_frame_get_argument(
215 struct psi_call_frame
*frame
, const char *name
) {
216 return zend_hash_str_find_ptr(&frame
->arguments
, name
, strlen(name
));
219 size_t psi_call_frame_num_var_args(struct psi_call_frame
*frame
) {
220 return zend_hash_next_free_element(&frame
->arguments
);
223 size_t psi_call_frame_num_fixed_args(struct psi_call_frame
*frame
) {
224 return psi_plist_count(frame
->decl
->args
);
227 struct psi_call_frame_argument
*psi_call_frame_get_var_argument(
228 struct psi_call_frame
*frame
, zend_long index
) {
229 return zend_hash_index_find_ptr(&frame
->arguments
, index
);
232 void **psi_call_frame_get_arg_pointers(struct psi_call_frame
*frame
) {
233 return frame
->pointers
;
236 ZEND_RESULT_CODE
psi_call_frame_parse_args(struct psi_call_frame
*frame
,
237 zend_execute_data
*execute_data
) {
238 size_t i
, argc
= psi_plist_count(frame
->impl
->func
->args
);
239 zend_error_handling zeh
;
241 zend_replace_error_handling(EH_THROW
, zend_exception_get_default(), &zeh
);
246 rv
= zend_parse_parameters_none();
247 zend_restore_error_handling(&zeh
);
251 ZEND_PARSE_PARAMETERS_START(
252 psi_impl_num_min_args(frame
->impl
),
253 frame
->impl
->func
->vararg
? -1 : argc
257 struct psi_impl_arg
*iarg
;
260 if (frame
->impl
->func
->vararg
&& _i
>= argc
) {
261 iarg
= frame
->impl
->func
->vararg
;
264 psi_plist_get(frame
->impl
->func
->args
, _i
, &iarg
);
270 if (PSI_T_BOOL
== iarg
->type
->type
) {
271 Z_PARAM_BOOL(ival
.zend
.bval
);
272 } else if (PSI_T_INT
== iarg
->type
->type
) {
273 Z_PARAM_LONG(ival
.zend
.lval
);
274 } else if (PSI_T_FLOAT
== iarg
->type
->type
|| PSI_T_DOUBLE
== iarg
->type
->type
) {
275 Z_PARAM_DOUBLE(ival
.dval
);
276 } else if (PSI_T_STRING
== iarg
->type
->type
) {
277 Z_PARAM_STR_EX(ival
.zend
.str
, 1, iarg
->var
->reference
);
279 zend_string_addref(ival
.zend
.str
);
281 } else if (PSI_T_ARRAY
== iarg
->type
->type
) {
283 Z_PARAM_ARRAY_EX(tmp
, _optional
|| iarg
->var
->reference
,
284 iarg
->var
->reference
);
285 } else if (PSI_T_OBJECT
== iarg
->type
->type
) {
286 Z_PARAM_PROLOGUE(iarg
->var
->reference
);
287 } else if (PSI_T_MIXED
== iarg
->type
->type
) {
288 Z_PARAM_PROLOGUE(iarg
->var
->reference
);
289 } else if (PSI_T_CALLABLE
== iarg
->type
->type
) {
291 zend_fcall_info_cache fcc
;
293 Z_PARAM_FUNC_EX(fci
, fcc
, 1, 0);
296 ival
.zend
.cb
= ecalloc(1, sizeof(zend_fcall
));
297 ival
.zend
.cb
->fci
= fci
;
298 ival
.zend
.cb
->fcc
= fcc
;
301 error_code
= ZPP_ERROR_FAILURE
;
305 psi_call_frame_new_argument(frame
,
306 psi_call_frame_argument_init(iarg
, &ival
, _arg
, _i
> argc
));
308 if (_i
< _num_args
) {
312 ZEND_PARSE_PARAMETERS_END_EX(
313 zend_restore_error_handling(&zeh
);
317 /* set up defaults */
318 for (i
= EX_NUM_ARGS(); i
< argc
; ++i
) {
319 struct psi_impl_arg
*iarg
;
321 psi_plist_get(frame
->impl
->func
->args
, i
, &iarg
);
324 psi_call_frame_new_argument(frame
, psi_call_frame_argument_init(iarg
,
325 &iarg
->def
->ival
, NULL
, 0));
328 zend_restore_error_handling(&zeh
);
332 void psi_call_frame_enter(struct psi_call_frame
*frame
) {
333 size_t argc
= psi_call_frame_num_fixed_args(frame
);
334 size_t va_count
= psi_call_frame_num_var_args(frame
);
335 size_t rsize
= psi_decl_arg_get_size(frame
->decl
->func
);
336 struct psi_call_frame_symbol
*rv_sym
;
338 /* initialize ffi argument array */
339 frame
->pointers
= ecalloc(argc
+ va_count
+ 1, sizeof(void *));
341 /* initialize return value symbol */
342 rv_sym
= psi_call_frame_fetch_symbol(frame
, frame
->decl
->func
->var
);
343 if (rsize
> sizeof(impl_val
)) {
344 rv_sym
->ival_ptr
= ecalloc(1, rsize
);
346 rv_sym
->ival_ptr
= &rv_sym
->temp_val
;
348 frame
->rpointer
= rv_sym
->ptr
= rv_sym
->ival_ptr
;
351 ZEND_RESULT_CODE
psi_call_frame_do_let(struct psi_call_frame
*frame
) {
353 struct psi_let_stmt
*let
;
354 struct psi_decl_arg
*arg
;
355 size_t argc
= psi_call_frame_num_fixed_args(frame
);
356 size_t va_count
= psi_call_frame_num_var_args(frame
);
358 for (i
= 0; psi_plist_get(frame
->impl
->stmts
.let
, i
, &let
); ++i
) {
359 psi_let_stmt_exec(let
, frame
);
361 for (i
= 0; psi_plist_get(frame
->decl
->args
, i
, &arg
); ++i
) {
362 struct psi_let_stmt
*let
;
363 struct psi_call_frame_symbol
*frame_sym
;
365 let
= psi_impl_get_let(frame
->impl
, arg
->var
);
366 frame_sym
= psi_call_frame_fetch_symbol(frame
, let
->exp
->var
);
367 frame
->pointers
[i
] = frame_sym
->ptr
;
371 for (i
= 0; i
< va_count
; ++i
) {
372 struct psi_call_frame_argument
*frame_arg
;
373 psi_marshal_let let_fn
;
376 frame_arg
= psi_call_frame_get_var_argument(frame
, i
);
377 switch (frame_arg
->va_type
) {
378 case PSI_T_BOOL
: let_fn
= psi_let_boolval
; break;
379 case PSI_T_INT
: let_fn
= psi_let_intval
; break;
381 case PSI_T_DOUBLE
: let_fn
= psi_let_floatval
; break;
382 case PSI_T_STRING
: let_fn
= psi_let_strval
; break;
387 frame_arg
->ival_ptr
= let_fn(&frame_arg
->temp_val
, NULL
, frame_arg
->va_type
,
388 &frame_arg
->ival
, frame_arg
->zval_ptr
, &temp
);
390 psi_call_frame_push_auto(frame
, temp
);
393 frame
->pointers
[argc
+ i
] = frame_arg
->ival_ptr
;
400 void psi_call_frame_do_call(struct psi_call_frame
*frame
) {
401 size_t va_count
= psi_call_frame_num_var_args(frame
);
404 void **va_types
= ecalloc(va_count
, sizeof(void *));
407 for (i
= 0; i
< va_count
; ++i
) {
408 struct psi_call_frame_argument
*frame_arg
;
410 frame_arg
= psi_call_frame_get_var_argument(frame
, i
);
411 va_types
[i
] = frame
->context
->ops
->query(frame
->context
,
412 PSI_CONTEXT_QUERY_TYPE
, &frame_arg
->va_type
);
415 frame
->context
->ops
->call_va(frame
->context
,
425 frame
->context
->ops
->call(frame
->context
,
433 void psi_call_frame_do_callback(struct psi_call_frame
*frame
, struct psi_call_frame_callback
*cbdata
)
438 struct psi_let_callback
*cb
= cbdata
->cb
->data
.callback
;
439 zval return_value
, *zargv
= ecalloc(cbdata
->argc
, sizeof(*zargv
));
440 struct psi_call_frame_argument
*frame_arg
;
442 assert(cbdata
->argc
== psi_plist_count(cb
->decl
->args
));
444 /* prepare args for the userland call */
445 for (i
= 0; i
< cbdata
->argc
; ++i
) {
446 struct psi_set_exp
*set_exp
;
447 struct psi_decl_var
*set_var
;
448 struct psi_call_frame_symbol
*set_sym
;
450 psi_plist_get(cb
->args
, i
, &set_exp
);
451 set_var
= psi_set_exp_get_decl_var(set_exp
);
452 set_sym
= psi_call_frame_fetch_symbol(frame
, set_var
);
454 set_sym
->ptr
= cbdata
->argv
[i
];
455 psi_set_exp_exec_ex(set_exp
, &zargv
[i
], set_sym
->ptr
, frame
);
458 frame_arg
= psi_call_frame_get_argument(frame
, cb
->func
->var
->fqn
);
460 /* callback into userland */
461 ZVAL_UNDEF(&return_value
);
462 zend_fcall_info_argp(&frame_arg
->ival_ptr
->zend
.cb
->fci
, cbdata
->argc
, zargv
);
463 rc
= zend_fcall_info_call(&frame_arg
->ival_ptr
->zend
.cb
->fci
,
464 &frame_arg
->ival_ptr
->zend
.cb
->fcc
, &return_value
, NULL
);
465 assert(rc
== SUCCESS
);
467 /* marshal return value of the userland call */
468 frame_arg
->zval_ptr
= &return_value
;
469 retptr
= psi_let_func_exec(cbdata
->cb
, cb
->func
, cb
->decl
->func
, frame
);
470 memcpy(cbdata
->rval
, retptr
, psi_decl_arg_get_size(cb
->decl
->func
));
473 zend_fcall_info_args_clear(&frame_arg
->ival_ptr
->zend
.cb
->fci
, 0);
474 for (i
= 0; i
< cbdata
->argc
; ++i
) {
475 zval_ptr_dtor(&zargv
[i
]);
480 void psi_call_frame_do_return(struct psi_call_frame
*frame
, zval
*return_value
) {
481 struct psi_return_stmt
*ret
;
483 psi_plist_get(frame
->impl
->stmts
.ret
, 0, &ret
);
484 psi_return_stmt_exec(ret
, return_value
, frame
);
487 void psi_call_frame_do_set(struct psi_call_frame
*frame
) {
489 struct psi_set_stmt
*set
;
491 while (psi_plist_get(frame
->impl
->stmts
.set
, i
++, &set
)) {
492 psi_set_stmt_exec(set
, frame
);
496 void psi_call_frame_do_free(struct psi_call_frame
*frame
) {
498 struct psi_free_stmt
*fre
;
500 while (psi_plist_get(frame
->impl
->stmts
.fre
, i
++, &fre
)) {
501 psi_free_stmt_exec(fre
, frame
);
505 void **psi_call_frame_push_auto_ex(struct psi_call_frame
*frame
, void *auto_free
, void (*dtor
)(void*)) {
506 struct psi_call_frame_auto_free f
;
511 zend_llist_add_element(&frame
->temp
, &f
);
512 return &((struct psi_call_frame_auto_free
*) zend_llist_get_last(&frame
->temp
))->data
;
515 void **psi_call_frame_push_auto(struct psi_call_frame
*frame
, void *auto_free
) {
516 return psi_call_frame_push_auto_ex(frame
, auto_free
, NULL
);
519 static void psi_call_frame_local_auto_dtor(void *auto_list
)
521 zend_llist_destroy(auto_list
);
527 void psi_call_frame_free(struct psi_call_frame
*frame
) {
528 zend_hash_destroy(&frame
->arguments
);
529 zend_hash_destroy(&frame
->symbols
);
530 if (frame
->impl
&& frame
->impl
->func
->static_memory
) {
531 zend_llist
*temp
= emalloc(sizeof(*temp
));
534 memcpy(temp
, &frame
->temp
, sizeof(*temp
));
535 ZVAL_OBJ(&zlocal
, psi_object_init_ex(NULL
, temp
, psi_call_frame_local_auto_dtor
));
536 zend_set_local_var_str(frame
->impl
->func
->name
,
537 strlen(frame
->impl
->func
->name
), &zlocal
, /* force */ 1);
539 zend_llist_destroy(&frame
->temp
);
541 efree(frame
->pointers
);