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 ZVAL_NULL(&empty_zval
);
191 inner_zval
= zend_symtable_str_update(Z_ARRVAL_P(outer_zval
),
192 &inner_var
->name
[1], strlen(&inner_var
->name
[1]),
196 iarg
= psi_call_frame_get_argument(frame
, name
);
199 struct psi_call_frame_argument
*frame_arg
;
200 impl_val empty_val
= {0};
201 struct psi_impl_arg
*carg_spec
= psi_impl_arg_init(
202 psi_impl_type_init(PSI_T_MIXED
, "mixed"),
203 psi_impl_var_copy(inner_var
), NULL
);
205 psi_call_frame_push_auto_ex(frame
, carg_spec
, (void(*)(void*)) psi_impl_arg_free
);
206 frame_arg
= psi_call_frame_argument_init(carg_spec
, &empty_val
, inner_zval
, 0);
207 zend_hash_str_add_ptr(&frame
->arguments
, name
, strlen(name
), frame_arg
);
213 struct psi_call_frame_argument
*psi_call_frame_get_argument(
214 struct psi_call_frame
*frame
, const char *name
) {
215 return zend_hash_str_find_ptr(&frame
->arguments
, name
, strlen(name
));
218 size_t psi_call_frame_num_var_args(struct psi_call_frame
*frame
) {
219 return zend_hash_next_free_element(&frame
->arguments
);
222 size_t psi_call_frame_num_fixed_args(struct psi_call_frame
*frame
) {
223 return psi_plist_count(frame
->decl
->args
);
226 struct psi_call_frame_argument
*psi_call_frame_get_var_argument(
227 struct psi_call_frame
*frame
, zend_long index
) {
228 return zend_hash_index_find_ptr(&frame
->arguments
, index
);
231 void **psi_call_frame_get_arg_pointers(struct psi_call_frame
*frame
) {
232 return frame
->pointers
;
235 ZEND_RESULT_CODE
psi_call_frame_parse_args(struct psi_call_frame
*frame
,
236 zend_execute_data
*execute_data
) {
237 size_t i
, argc
= psi_plist_count(frame
->impl
->func
->args
);
238 zend_error_handling zeh
;
240 zend_replace_error_handling(EH_THROW
, zend_exception_get_default(), &zeh
);
245 rv
= zend_parse_parameters_none();
246 zend_restore_error_handling(&zeh
);
250 ZEND_PARSE_PARAMETERS_START(
251 psi_impl_num_min_args(frame
->impl
),
252 frame
->impl
->func
->vararg
? -1 : argc
256 struct psi_impl_arg
*iarg
;
259 if (frame
->impl
->func
->vararg
&& _i
>= argc
) {
260 iarg
= frame
->impl
->func
->vararg
;
263 psi_plist_get(frame
->impl
->func
->args
, _i
, &iarg
);
269 if (PSI_T_BOOL
== iarg
->type
->type
) {
270 Z_PARAM_BOOL(ival
.zend
.bval
);
271 } else if (PSI_T_INT
== iarg
->type
->type
) {
272 Z_PARAM_LONG(ival
.zend
.lval
);
273 } else if (PSI_T_FLOAT
== iarg
->type
->type
|| PSI_T_DOUBLE
== iarg
->type
->type
) {
274 Z_PARAM_DOUBLE(ival
.dval
);
275 } else if (PSI_T_STRING
== iarg
->type
->type
) {
276 Z_PARAM_STR_EX(ival
.zend
.str
, 1, iarg
->var
->reference
);
278 zend_string_addref(ival
.zend
.str
);
280 } else if (PSI_T_ARRAY
== iarg
->type
->type
) {
282 Z_PARAM_ARRAY_EX(tmp
, _optional
|| iarg
->var
->reference
,
283 iarg
->var
->reference
);
284 } else if (PSI_T_OBJECT
== iarg
->type
->type
) {
286 } else if (PSI_T_MIXED
== iarg
->type
->type
) {
288 } else if (PSI_T_CALLABLE
== iarg
->type
->type
) {
290 zend_fcall_info_cache fcc
;
292 Z_PARAM_FUNC_EX(fci
, fcc
, 1, 0);
295 ival
.zend
.cb
= ecalloc(1, sizeof(zend_fcall
));
296 ival
.zend
.cb
->fci
= fci
;
297 ival
.zend
.cb
->fcc
= fcc
;
300 error_code
= ZPP_ERROR_FAILURE
;
304 psi_call_frame_new_argument(frame
,
305 psi_call_frame_argument_init(iarg
, &ival
, _arg
, _i
> argc
));
307 if (_i
< _num_args
) {
311 ZEND_PARSE_PARAMETERS_END_EX(
312 zend_restore_error_handling(&zeh
);
316 /* set up defaults */
317 for (i
= EX_NUM_ARGS(); i
< argc
; ++i
) {
318 struct psi_impl_arg
*iarg
;
320 psi_plist_get(frame
->impl
->func
->args
, i
, &iarg
);
323 psi_call_frame_new_argument(frame
, psi_call_frame_argument_init(iarg
,
324 &iarg
->def
->ival
, NULL
, 0));
327 zend_restore_error_handling(&zeh
);
331 void psi_call_frame_enter(struct psi_call_frame
*frame
) {
332 size_t argc
= psi_call_frame_num_fixed_args(frame
);
333 size_t va_count
= psi_call_frame_num_var_args(frame
);
334 size_t rsize
= psi_decl_arg_get_size(frame
->decl
->func
);
335 struct psi_call_frame_symbol
*rv_sym
;
337 /* initialize ffi argument array */
338 frame
->pointers
= ecalloc(argc
+ va_count
+ 1, sizeof(void *));
340 /* initialize return value symbol */
341 rv_sym
= psi_call_frame_fetch_symbol(frame
, frame
->decl
->func
->var
);
342 if (rsize
> sizeof(impl_val
)) {
343 rv_sym
->ival_ptr
= ecalloc(1, rsize
);
345 rv_sym
->ival_ptr
= &rv_sym
->temp_val
;
347 frame
->rpointer
= rv_sym
->ptr
= rv_sym
->ival_ptr
;
350 ZEND_RESULT_CODE
psi_call_frame_do_let(struct psi_call_frame
*frame
) {
352 struct psi_let_stmt
*let
;
353 struct psi_decl_arg
*arg
;
354 size_t argc
= psi_call_frame_num_fixed_args(frame
);
355 size_t va_count
= psi_call_frame_num_var_args(frame
);
357 for (i
= 0; psi_plist_get(frame
->impl
->stmts
.let
, i
, &let
); ++i
) {
358 psi_let_stmt_exec(let
, frame
);
360 for (i
= 0; psi_plist_get(frame
->decl
->args
, i
, &arg
); ++i
) {
361 struct psi_let_stmt
*let
;
362 struct psi_call_frame_symbol
*frame_sym
;
364 let
= psi_impl_get_let(frame
->impl
, arg
->var
);
365 frame_sym
= psi_call_frame_fetch_symbol(frame
, let
->exp
->var
);
366 frame
->pointers
[i
] = frame_sym
->ptr
;
370 for (i
= 0; i
< va_count
; ++i
) {
371 struct psi_call_frame_argument
*frame_arg
;
372 psi_marshal_let let_fn
;
375 frame_arg
= psi_call_frame_get_var_argument(frame
, i
);
376 switch (frame_arg
->va_type
) {
377 case PSI_T_BOOL
: let_fn
= psi_let_boolval
; break;
378 case PSI_T_INT
: let_fn
= psi_let_intval
; break;
380 case PSI_T_DOUBLE
: let_fn
= psi_let_floatval
; break;
381 case PSI_T_STRING
: let_fn
= psi_let_strval
; break;
386 frame_arg
->ival_ptr
= let_fn(&frame_arg
->temp_val
, NULL
, frame_arg
->va_type
,
387 &frame_arg
->ival
, frame_arg
->zval_ptr
, &temp
);
389 psi_call_frame_push_auto(frame
, temp
);
392 frame
->pointers
[argc
+ i
] = frame_arg
->ival_ptr
;
399 void psi_call_frame_do_call(struct psi_call_frame
*frame
) {
400 size_t va_count
= psi_call_frame_num_var_args(frame
);
403 void **va_types
= ecalloc(va_count
, sizeof(void *));
406 for (i
= 0; i
< va_count
; ++i
) {
407 struct psi_call_frame_argument
*frame_arg
;
409 frame_arg
= psi_call_frame_get_var_argument(frame
, i
);
410 va_types
[i
] = frame
->context
->ops
->query(frame
->context
,
411 PSI_CONTEXT_QUERY_TYPE
, &frame_arg
->va_type
);
414 frame
->context
->ops
->call_va(frame
->context
,
424 frame
->context
->ops
->call(frame
->context
,
432 void psi_call_frame_do_callback(struct psi_call_frame
*frame
, struct psi_call_frame_callback
*cbdata
)
437 struct psi_let_callback
*cb
= cbdata
->cb
->data
.callback
;
438 zval return_value
, *zargv
= ecalloc(cbdata
->argc
, sizeof(*zargv
));
439 struct psi_call_frame_argument
*frame_arg
;
441 assert(cbdata
->argc
== psi_plist_count(cb
->decl
->args
));
443 /* prepare args for the userland call */
444 for (i
= 0; i
< cbdata
->argc
; ++i
) {
445 struct psi_set_exp
*set_exp
;
446 struct psi_decl_var
*set_var
;
447 struct psi_call_frame_symbol
*set_sym
;
449 psi_plist_get(cb
->args
, i
, &set_exp
);
450 set_var
= psi_set_exp_get_decl_var(set_exp
);
451 set_sym
= psi_call_frame_fetch_symbol(frame
, set_var
);
453 set_sym
->ptr
= cbdata
->argv
[i
];
454 psi_set_exp_exec_ex(set_exp
, &zargv
[i
], set_sym
->ptr
, frame
);
457 frame_arg
= psi_call_frame_get_argument(frame
, cb
->func
->var
->fqn
);
459 /* callback into userland */
460 ZVAL_UNDEF(&return_value
);
461 zend_fcall_info_argp(&frame_arg
->ival_ptr
->zend
.cb
->fci
, cbdata
->argc
, zargv
);
462 rc
= zend_fcall_info_call(&frame_arg
->ival_ptr
->zend
.cb
->fci
,
463 &frame_arg
->ival_ptr
->zend
.cb
->fcc
, &return_value
, NULL
);
464 assert(rc
== SUCCESS
);
466 /* marshal return value of the userland call */
467 frame_arg
->zval_ptr
= &return_value
;
468 retptr
= psi_let_func_exec(cbdata
->cb
, cb
->func
, cb
->decl
->func
, frame
);
469 memcpy(cbdata
->rval
, retptr
, psi_decl_arg_get_size(cb
->decl
->func
));
472 zend_fcall_info_args_clear(&frame_arg
->ival_ptr
->zend
.cb
->fci
, 0);
473 for (i
= 0; i
< cbdata
->argc
; ++i
) {
474 zval_ptr_dtor(&zargv
[i
]);
479 void psi_call_frame_do_return(struct psi_call_frame
*frame
, zval
*return_value
) {
480 struct psi_return_stmt
*ret
;
482 psi_plist_get(frame
->impl
->stmts
.ret
, 0, &ret
);
483 psi_return_stmt_exec(ret
, return_value
, frame
);
486 void psi_call_frame_do_set(struct psi_call_frame
*frame
) {
488 struct psi_set_stmt
*set
;
490 while (psi_plist_get(frame
->impl
->stmts
.set
, i
++, &set
)) {
491 psi_set_stmt_exec(set
, frame
);
495 void psi_call_frame_do_free(struct psi_call_frame
*frame
) {
497 struct psi_free_stmt
*fre
;
499 while (psi_plist_get(frame
->impl
->stmts
.fre
, i
++, &fre
)) {
500 psi_free_stmt_exec(fre
, frame
);
504 void **psi_call_frame_push_auto_ex(struct psi_call_frame
*frame
, void *auto_free
, void (*dtor
)(void*)) {
505 struct psi_call_frame_auto_free f
;
510 zend_llist_add_element(&frame
->temp
, &f
);
511 return &((struct psi_call_frame_auto_free
*) zend_llist_get_last(&frame
->temp
))->data
;
514 void **psi_call_frame_push_auto(struct psi_call_frame
*frame
, void *auto_free
) {
515 return psi_call_frame_push_auto_ex(frame
, auto_free
, NULL
);
518 static void psi_call_frame_local_auto_dtor(void *auto_list
)
520 zend_llist_destroy(auto_list
);
526 void psi_call_frame_free(struct psi_call_frame
*frame
) {
527 zend_hash_destroy(&frame
->arguments
);
528 zend_hash_destroy(&frame
->symbols
);
529 if (frame
->impl
&& frame
->impl
->func
->static_memory
) {
530 zend_llist
*temp
= emalloc(sizeof(*temp
));
533 memcpy(temp
, &frame
->temp
, sizeof(*temp
));
534 ZVAL_OBJ(&zlocal
, psi_object_init_ex(NULL
, temp
, psi_call_frame_local_auto_dtor
));
535 zend_set_local_var_str(frame
->impl
->func
->name
,
536 strlen(frame
->impl
->func
->name
), &zlocal
, /* force */ 1);
538 zend_llist_destroy(&frame
->temp
);
540 efree(frame
->pointers
);