From: Michael Wallner Date: Wed, 27 Jan 2016 10:14:53 +0000 (+0100) Subject: code structure X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=commitdiff_plain;h=b4a3c33fc143fd57288fcfe0878e7a22eeaf61bf code structure --- diff --git a/.gitignore b/.gitignore index 4979790..ec1ac8e 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,5 @@ php_psi_stdtypes.h php_psi_structs.h php_psi_types.h php_psi_va_decls.h +/tmp/ +*.loT diff --git a/config.m4 b/config.m4 index e2a28dd..16db302 100644 --- a/config.m4 +++ b/config.m4 @@ -105,8 +105,10 @@ if test "$PHP_PSI" != no; then PHP_ADD_BUILD_DIR($PHP_PSI_BUILDDIR/src) PHP_PSI_HEADERS=`(cd $PHP_PSI_SRCDIR/src && echo *.h)` - PHP_PSI_SOURCES="src/parser_proc.c src/parser.c src/module.c src/context.c" - PHP_PSI_SOURCES="$PHP_PSI_SOURCES src/libjit.c src/libffi.c" + PHP_PSI_SOURCES=`(cd $PHP_PSI_SRCDIR && echo src/context*.c)` + PHP_PSI_SOURCES="$PHP_PSI_SOURCES src/parser_proc.c src/parser.c" + PHP_PSI_SOURCES="$PHP_PSI_SOURCES src/libjit.c src/libffi.c src/engine.c" + PHP_PSI_SOURCES="$PHP_PSI_SOURCES src/marshal.c src/calc.c src/module.c" PHP_NEW_EXTENSION(psi, $PHP_PSI_SOURCES, $ext_shared) PHP_INSTALL_HEADERS(ext/psi, php_psi.h $PHP_PSI_HEADERS) diff --git a/idl/Makefile b/idl/Makefile deleted file mode 100644 index 450905e..0000000 --- a/idl/Makefile +++ /dev/null @@ -1,52 +0,0 @@ -PHP_INCLUDES := -I/Users/Mike/Sources/php-src.git/{.,main,includes,Zend,TSRM,ext} -JIT_INCLUDES := -I/usr/local/include -UNAME := $(shell uname | tr a-z A-Z) -INCLUDES += $(PHP_INCLUDES) $(JIT_INCLUDES) -CFLAGS += -g -D$(UNAME) $(INCLUDES) -LDFLAGS += -ljit -ljitdynamic /usr/local/php7/lib/libphp7.dylib -Xlinker -rpath -Xlinker /usr/local/php7/lib -SOURCES := parser_proc.c parser.c validator.c compiler.c main.c - -GENERATED_FILES := $(addsuffix .h, $(basename $(SOURCES))) - -.PHONY: all -all: main - -## -# The lemon parser generator -## -GENERATED_FILES += lempar.c -lempar.c: - curl -sSo $@ "http://www.sqlite.org/src/raw/tool/lempar.c?name=3617143ddb9b176c3605defe6a9c798793280120" - -GENERATED_FILES += lemon.c -lemon.c: - curl -sSo $@ "http://www.sqlite.org/src/raw/tool/lemon.c?name=039f813b520b9395740c52f9cbf36c90b5d8df03" - -GENERATED_FILES += lemon -lemon: lemon.c | lempar.c - -## -# Main test program -## -$(SOURCES): Makefile - -GENERATED_FILES += main -main: $(SOURCES) - -## -# Parser proc -## -GENERATED_FILES += parser_proc.c -parser_proc.c: parser_proc.y lemon - ./lemon -c $< - -## -# Parser with lexer -## -GENERATED_FILES += parser.c -parser.c: parser.re - re2c -o $@ $< - -.PHONY: clean -clean: - -echo rm -f $(GENERATED_FILES) diff --git a/idl/main.c b/idl/main.c deleted file mode 100644 index db88740..0000000 --- a/idl/main.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include - -#include "parser.h" -#include "validator.h" - -int main(int argc, char *argv[]) -{ - PSI_Parser P; - PSI_Validator V; - unsigned flags = 0; - - if (getenv("TRACE")) { - flags |= PSI_PARSER_DEBUG; - } - - if (!PSI_ParserInit(&P, argv[1], flags)) { - perror("Failer to init parser"); - return 1; - } - - while (-1 != PSI_ParserScan(&P)) { - PSI_ParserParse(&P, PSI_TokenAlloc(&P)); - }; - PSI_ParserParse(&P, NULL); - - if (!PSI_ValidatorInit(&V, &P)) { - perror("Failed to init validator"); - return 2; - } - - PSI_ParserDtor(&P); - - if (PSI_ValidatorValidate(&V)) { - printf("Whoa! VALID.\n"); - } - PSI_ValidatorDtor(&V); - - return 0; -} diff --git a/m4/psi.m4 b/m4/psi.m4 index c9f4e08..97ea6fe 100644 --- a/m4/psi.m4 +++ b/m4/psi.m4 @@ -16,7 +16,7 @@ dnl This macro must be called prior any checks for a type, struct, decl etc. AC_DEFUN(PSI_CONFIG_INIT, [ cat >$PSI_STDTYPES <$PSI_TYPES <@ = { +static struct psi_predef_type { + token_t type_tag; + const char *type_name; + const char *alias; +} psi_predef_types@<:@@:>@ = { EOF cat >$PSI_STRUCTS <handlers->offset); } -size_t psi_t_alignment(token_t t); -size_t psi_t_size(token_t t); -size_t psi_t_align(token_t t, size_t s); - -size_t psi_offset_padding(size_t diff, size_t alignment); -int psi_internal_type(impl_type *type); -zend_internal_arg_info *psi_internal_arginfo(impl *impl); -size_t psi_num_min_args(impl *impl); - -void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val); -void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val); -void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val); -void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val); -void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val); -void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val); -void psi_to_array(zval *return_value, set_value *set, impl_val *ret_val); -void psi_to_object(zval *return_value, set_value *set, impl_val *ret_val); - -void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl); - -int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res); - -static inline zend_long psi_long_num_exp(num_exp *exp, impl_val *strct) { - impl_val val = {0}; - - switch (psi_calc_num_exp(exp, strct, &val)) { - case PSI_T_UINT8: return val.u8; - case PSI_T_UINT16: return val.u16; - case PSI_T_UINT32: return val.u32; - case PSI_T_UINT64: return val.u64; /* FIXME */ - case PSI_T_INT8: return val.i8; - case PSI_T_INT16: return val.i16; - case PSI_T_INT32: return val.i32; - case PSI_T_INT64: return val.i64; - case PSI_T_FLOAT: return val.fval; - case PSI_T_DOUBLE: return val.dval; - EMPTY_SWITCH_DEFAULT_CASE(); - } - return 0; -} - -int psi_calc_add(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res); -int psi_calc_sub(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res); -int psi_calc_mul(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res); -int psi_calc_div(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res); +PHP_PSI_API zend_class_entry *psi_object_get_class_entry(); ZEND_BEGIN_MODULE_GLOBALS(psi) char *engine; @@ -94,6 +50,8 @@ ZEND_BEGIN_MODULE_GLOBALS(psi) PSI_Context context; ZEND_END_MODULE_GLOBALS(psi); +ZEND_EXTERN_MODULE_GLOBALS(psi); + #define PSI_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(psi, v) #if defined(ZTS) && defined(COMPILE_DL_PSI) diff --git a/src/calc.c b/src/calc.c new file mode 100644 index 0000000..fc3e043 --- /dev/null +++ b/src/calc.c @@ -0,0 +1,285 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_psi.h" + +static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *strct, impl_val *res) { + impl_val *ref, *tmp = NULL; + + switch (exp->t) { + case PSI_T_NUMBER: + switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) res, (double *) res, 0)) { + case IS_LONG: + return PSI_T_INT64; + case IS_DOUBLE: + return PSI_T_DOUBLE; + } + break; + + case PSI_T_NSNAME: + switch (exp->u.cnst->type->type) { + case PSI_T_INT: + res->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval; + return PSI_T_INT64; + case PSI_T_FLOAT: + res->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval; + return PSI_T_DOUBLE; + default: + return 0; + } + break; + + case PSI_T_NAME: + if (strct) { + ref = struct_member_ref(exp->u.dvar->arg, strct, &tmp); + } else if (exp->u.dvar->arg->let) { + ref = exp->u.dvar->arg->let->ptr; + } else { + ref = exp->u.dvar->arg->ptr; + } + switch (real_decl_type(exp->u.dvar->arg->type)->type) { + case PSI_T_INT8: + case PSI_T_UINT8: + case PSI_T_INT16: + case PSI_T_UINT16: + case PSI_T_INT32: + case PSI_T_UINT32: + case PSI_T_INT64: + case PSI_T_UINT64: + memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res)); + if (tmp) { + free(tmp); + } + return real_decl_type(exp->u.dvar->arg->type)->type; + + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res)); + if (tmp) { + free(tmp); + } + return real_decl_type(exp->u.dvar->arg->type)->type; + + EMPTY_SWITCH_DEFAULT_CASE(); + } + break; + + EMPTY_SWITCH_DEFAULT_CASE(); + } + return 0; +} + +int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) { + impl_val num = {0}; + int num_type = psi_calc_num_exp_value(exp, strct, &num); + + if (exp->operand) { + impl_val tmp = {0}; + int tmp_type = psi_calc_num_exp(exp->operand, strct, &tmp); + + return exp->calculator(num_type, &num, tmp_type, &tmp, res); + } + + memcpy(res, &num, sizeof(*res)); + return num_type; +} + +#define PRIfval "f" +#define PRIdval "lf" +#define PRIldval "Lf" + +#define PSI_CALC_OP(var) do { \ + const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \ + res->var = PSI_CALC(v1->var, v2->var); \ + if (!res->var) fprintf(stderr, fmt, v1->var, v2->var, res->var); \ +} while (0) +#define PSI_CALC_OP2(vres, var1, var2) do { \ + const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \ + res->vres = PSI_CALC(v1->var1, v2->var2); \ + if (!res->vres) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \ +} while(0) + +#ifdef HAVE_LONG_DOUBLE +#define PSI_CALC_NO_LD +#define PSI_CALC_OP_LD PSI_CALC_OP(ldval) +#define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval) +#define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2) +#else +#define PSI_CALC_NO_LD abort() +#define PSI_CALC_OP_LD PSI_CALC_NO_LD +#define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD +#define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD +#endif + +#define PSI_CALC_FN(op) int psi_calc_##op(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res) \ +{ \ + if (t1 == t2) { \ + switch (t1) { \ + case PSI_T_FLOAT: PSI_CALC_OP(fval); break; \ + case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; \ + case PSI_T_LONG_DOUBLE: PSI_CALC_OP_LD; break; \ + case PSI_T_INT8: PSI_CALC_OP(i8); break; \ + case PSI_T_UINT8: PSI_CALC_OP(u8); break; \ + case PSI_T_INT16: PSI_CALC_OP(i16); break; \ + case PSI_T_UINT16: PSI_CALC_OP(u16); break; \ + case PSI_T_INT32: PSI_CALC_OP(i32); break; \ + case PSI_T_UINT32: PSI_CALC_OP(u32); break; \ + case PSI_T_INT64: PSI_CALC_OP(i64); break; \ + case PSI_T_UINT64: PSI_CALC_OP(u64); break; \ + EMPTY_SWITCH_DEFAULT_CASE(); \ + } \ + return t1; \ + } else if (t1 == PSI_T_DOUBLE) { \ + switch (t2) { \ + case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(dval); return t2; \ + case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; \ + case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; \ + case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; \ + case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; \ + case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; \ + case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; \ + case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; \ + case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; \ + case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; \ + EMPTY_SWITCH_DEFAULT_CASE(); \ + } \ + return t1; \ + } else if (t2 == PSI_T_DOUBLE) { \ + switch (t1) { \ + case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(dval); return t1; \ + case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; \ + case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; \ + case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; \ + case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; \ + case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; \ + case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; \ + case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; \ + case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; \ + case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; \ + EMPTY_SWITCH_DEFAULT_CASE(); \ + } \ + return t2; \ + } else if (t1 == PSI_T_LONG_DOUBLE) { \ + PSI_CALC_NO_LD; \ + switch (t2) { \ + case PSI_T_DOUBLE: PSI_CALC_OP2_LD1(dval); break; \ + case PSI_T_FLOAT: PSI_CALC_OP2_LD1(fval); break; \ + case PSI_T_INT8: PSI_CALC_OP2_LD1(i8); break; \ + case PSI_T_UINT8: PSI_CALC_OP2_LD1(u8); break; \ + case PSI_T_INT16: PSI_CALC_OP2_LD1(i16); break; \ + case PSI_T_UINT16: PSI_CALC_OP2_LD1(u16); break; \ + case PSI_T_INT32: PSI_CALC_OP2_LD1(i32); break; \ + case PSI_T_UINT32: PSI_CALC_OP2_LD1(u32); break; \ + case PSI_T_INT64: PSI_CALC_OP2_LD1(i64); break; \ + case PSI_T_UINT64: PSI_CALC_OP2_LD1(u64); break; \ + EMPTY_SWITCH_DEFAULT_CASE(); \ + } \ + return t1; \ + } else if (t2 == PSI_T_LONG_DOUBLE) { \ + PSI_CALC_NO_LD; \ + switch (t1) { \ + case PSI_T_DOUBLE: PSI_CALC_OP2_LD2(dval); break; \ + case PSI_T_FLOAT: PSI_CALC_OP2_LD2(fval); break; \ + case PSI_T_INT8: PSI_CALC_OP2_LD2(i8); break; \ + case PSI_T_UINT8: PSI_CALC_OP2_LD2(u8); break; \ + case PSI_T_INT16: PSI_CALC_OP2_LD2(i16); break; \ + case PSI_T_UINT16: PSI_CALC_OP2_LD2(u16); break; \ + case PSI_T_INT32: PSI_CALC_OP2_LD2(i32); break; \ + case PSI_T_UINT32: PSI_CALC_OP2_LD2(u32); break; \ + case PSI_T_INT64: PSI_CALC_OP2_LD2(i64); break; \ + case PSI_T_UINT64: PSI_CALC_OP2_LD2(u64); break; \ + EMPTY_SWITCH_DEFAULT_CASE(); \ + } \ + return t2; \ + } else if (t1 == PSI_T_FLOAT) { \ + switch (t2) { \ + case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(fval); return t2; \ + case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; \ + case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; \ + case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; \ + case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; \ + case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; \ + case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; \ + case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; \ + case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; \ + case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; \ + EMPTY_SWITCH_DEFAULT_CASE(); \ + } \ + return t1; \ + } else if (t2 == PSI_T_FLOAT) { \ + switch (t1) { \ + case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(fval); return t1; \ + case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; \ + case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; \ + case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; \ + case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; \ + case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; \ + case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; \ + case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; \ + case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; \ + case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; \ + EMPTY_SWITCH_DEFAULT_CASE(); \ + } \ + return t2; \ + } else { \ + int64_t sval1 = v1->i64, sval2 = v2->i64; \ + uint64_t uval1 = v1->u64, uval2 = v2->u64; \ + switch (t1) { \ + case PSI_T_INT8: sval1 >>= 8; \ + case PSI_T_INT16: sval1 >>= 8; \ + case PSI_T_INT32: sval1 >>= 8; \ + case PSI_T_INT64: \ + switch (t2) { \ + case PSI_T_INT8: sval2 >>= 8; \ + case PSI_T_INT16: sval2 >>= 8; \ + case PSI_T_INT32: sval2 >>= 8; \ + case PSI_T_INT64: \ + res->i64 = PSI_CALC(sval1 , sval2); \ + return PSI_T_INT64; \ + case PSI_T_UINT8: uval2 >>= 8; \ + case PSI_T_UINT16: uval2 >>= 8; \ + case PSI_T_UINT32: uval2 >>= 8; \ + case PSI_T_UINT64: \ + res->i64 = PSI_CALC(sval1, uval2); \ + return PSI_T_INT64; \ + } \ + break; \ + case PSI_T_UINT8: uval1 >>= 8; \ + case PSI_T_UINT16: uval1 >>= 8; \ + case PSI_T_UINT32: uval1 >>= 8; \ + case PSI_T_UINT64: \ + switch (t2) { \ + case PSI_T_INT8: sval2 >>= 8; \ + case PSI_T_INT16: sval2 >>= 8; \ + case PSI_T_INT32: sval2 >>= 8; \ + case PSI_T_INT64: \ + res->i64 = PSI_CALC(uval1, sval2); \ + return PSI_T_INT64; \ + case PSI_T_UINT8: uval2 >>= 8; \ + case PSI_T_UINT16: uval2 >>= 8; \ + case PSI_T_UINT32: uval2 >>= 8; \ + case PSI_T_UINT64: \ + res->u64 = PSI_CALC(uval1, uval2); \ + return PSI_T_UINT64; \ + } \ + break; \ + } \ + } \ + ZEND_ASSERT(0); \ + return 0; \ +} + +#undef PSI_CALC +#define PSI_CALC(var1, var2) (var1) + (var2) +PSI_CALC_FN(add) +#undef PSI_CALC +#define PSI_CALC(var1, var2) (var1) * (var2) +PSI_CALC_FN(mul) +#undef PSI_CALC +#define PSI_CALC(var1, var2) (var1) - (var2) +PSI_CALC_FN(sub) +#undef PSI_CALC +#define PSI_CALC(var1, var2) (var1) / (var2) +PSI_CALC_FN(div) diff --git a/src/calc.h b/src/calc.h new file mode 100644 index 0000000..d00aec0 --- /dev/null +++ b/src/calc.h @@ -0,0 +1,30 @@ +#ifndef _PSI_CALC_H +#define _PSI_CALC_H + +int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res); + +static inline zend_long psi_long_num_exp(num_exp *exp, impl_val *strct) { + impl_val val = {0}; + + switch (psi_calc_num_exp(exp, strct, &val)) { + case PSI_T_UINT8: return val.u8; + case PSI_T_UINT16: return val.u16; + case PSI_T_UINT32: return val.u32; + case PSI_T_UINT64: return val.u64; /* FIXME */ + case PSI_T_INT8: return val.i8; + case PSI_T_INT16: return val.i16; + case PSI_T_INT32: return val.i32; + case PSI_T_INT64: return val.i64; + case PSI_T_FLOAT: return val.fval; + case PSI_T_DOUBLE: return val.dval; + EMPTY_SWITCH_DEFAULT_CASE(); + } + return 0; +} + +int psi_calc_add(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res); +int psi_calc_sub(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res); +int psi_calc_mul(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res); +int psi_calc_div(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res); + +#endif diff --git a/src/context.c b/src/context.c index f0f2a6a..1887a7c 100644 --- a/src/context.c +++ b/src/context.c @@ -4,8 +4,6 @@ #include "php.h" -#include "php_psi_stdinc.h" - #ifdef HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen ((dirent)->d_name) @@ -23,8 +21,6 @@ # endif #endif -#include -#include #include #include "php.h" @@ -34,854 +30,15 @@ #include "libjit.h" #include "libffi.h" -#include "php_psi_stdtypes.h" #include "php_psi_types.h" #include "php_psi_consts.h" -#include "php_psi_macros.h" -#include "php_psi_redirs.h" #include "php_psi_decls.h" #include "php_psi_va_decls.h" #include "php_psi_structs.h" -static int validate_lib(PSI_Data *data, void **dlopened) { - char lib[MAXPATHLEN]; - const char *ptr = data->psi.file.ln; - size_t len; - - if (!ptr) { - /* FIXME: assume stdlib */ - return 1; - } else if (!strchr(ptr, '/')) { - len = snprintf(lib, MAXPATHLEN, "lib%s.%s", ptr, PHP_PSI_SHLIB_SUFFIX); - if (MAXPATHLEN == len) { - data->error(NULL, PSI_WARNING, "Library name too long: '%s'", ptr); - } - lib[len] = 0; - ptr = lib; - } - if (!(*dlopened = dlopen(ptr, RTLD_LAZY|RTLD_LOCAL))) { - data->error(NULL, PSI_WARNING, "Could not open library '%s': %s.", - data->psi.file.ln, dlerror()); - return 0; - } - return 1; -} - -static inline int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) { - size_t i; - struct psi_predef_type *stdtyp; - - if (type->real) { - return 1; - } - for (i = 0; i < defs->count; ++i) { - decl_typedef *def = defs->list[i]; - - if (def->type->type != type->type && !strcmp(def->alias, type->name)) { - type->real = def->type; - return 1; - } - } - for (stdtyp = &psi_std_types[0]; stdtyp->type_tag; ++stdtyp) { - if (!strcmp(type->name, stdtyp->alias ?: stdtyp->type_name)) { - type->type = stdtyp->type_tag; - return 1; - } - } - - return 0; -} -static inline int locate_decl_type_struct(decl_structs *structs, decl_type *type) { - size_t i; - - if (type->strct) { - return 1; - } - for (i = 0; i < structs->count; ++i) { - if (!strcmp(structs->list[i]->name, type->name)) { - type->strct = structs->list[i]; - return 1; - } - } - return 0; -} - -static inline int validate_decl_type(PSI_Data *data, decl_type *type) { - switch (type->type) { - case PSI_T_CHAR: - case PSI_T_SHORT: - case PSI_T_INT: - case PSI_T_LONG: - case PSI_T_NAME: - if (!data->defs || !locate_decl_type_alias(data->defs, type)) { - return 0; - } - if (type->real) { - return validate_decl_type(data, type->real); - } - return 1; - case PSI_T_STRUCT: - if (!data->structs || !locate_decl_type_struct(data->structs, type)) { - return 0; - } - break; - } - return 1; -} -static inline int validate_decl_typedef(PSI_Data *data, decl_typedef *def) { - if (!validate_decl_type(data, def->type)) { - data->error(def->token, PSI_WARNING, - "Type '%s' cannot be aliased to %s'%s'", - def->type->name, def->type->type == PSI_T_STRUCT?"struct ":"",def->alias); - return 0; - } - /* FIXME: check def->alias */ - return 1; -} - -static inline int validate_constant(PSI_Data *data, constant *c) { - /* FIXME */ - return 1; -} - -static inline int validate_decl_arg(PSI_Data *data, decl_arg *arg) { - if (!validate_decl_type(data, arg->type)) { - data->error(arg->type->token, PSI_WARNING, - "Cannot use '%s'(%d) as type for decl var '%s'", - arg->type->name, arg->type->type, arg->var->name); - return 0; - } - return 1; -} - -static int psi_sort_struct_arg_cmp(const void *_a, const void *_b) { - decl_arg *a = *(decl_arg **)_a, *b = *(decl_arg **)_b; - - if (a->layout->pos == b->layout->pos) { - if (a->layout->len == b->layout->len) { - return 0; - } else if (a->layout->len > b->layout->len) { - return -1; - } else { - return 1; - } - } else if (a->layout->pos > b->layout->pos) { - return 1; - } else { - return -1; - } -} -static void psi_sort_struct_arg_swp(void *a, void *b) { - decl_arg **_a = a, **_b = b, *_c; - - _c = *_b; - *_b = *_a; - *_a = _c; -} -static inline void psi_sort_struct_args(decl_struct *s) { - zend_insert_sort(s->args->args, s->args->count, sizeof(*s->args->args), - psi_sort_struct_arg_cmp, psi_sort_struct_arg_swp); -} - -static inline int validate_decl_struct(PSI_Data *data, decl_struct *s) { - size_t i; - - for (i = 0; i < s->args->count; ++i) { - if (!validate_decl_arg(data, s->args->args[i])) { - return 0; - } - } - - for (i = 0; i < s->args->count; ++i) { - decl_arg *darg = s->args->args[i]; - - if (!validate_decl_arg(data, darg)) { - return 0; - } - - ZEND_ASSERT(!darg->var->arg || darg->var->arg == darg); - darg->var->arg = darg; - - if (darg->layout) { - size_t size; - - if (darg->var->array_size) { - size = psi_t_size(real_decl_type(darg->type)->type) * darg->var->array_size; - } else if (darg->var->pointer_level) { - size = psi_t_size(PSI_T_POINTER); - } else { - decl_type *real = real_decl_type(darg->type); - - if (real->type == PSI_T_STRUCT) { - size = real->strct->size; - } else { - size = psi_t_size(real->type); - } - } - if (darg->layout->len != size) { - data->error(darg->token, PSI_WARNING, - "Computed length %zu of %s.%s does not match" - " pre-defined length %zu of type '%s'", - darg->layout->len, s->name, darg->var->name, size, - darg->type->name); - return 0; - } - } else { - token_t t; - - if (darg->var->pointer_level && (!darg->var->array_size || darg->var->pointer_level == 1)) { - t = PSI_T_POINTER; - } else { - t = real_decl_type(darg->type)->type; - } - - if (i) { - decl_arg *last = s->args->args[i-1]; - darg->layout = init_decl_struct_layout( - psi_t_align(t, last->layout->pos + last->layout->len), - psi_t_size(t) * darg->var->array_size); - } else { - darg->layout = init_decl_struct_layout(0, psi_t_size(t)); - } - } - if (s->size < darg->layout->pos + darg->layout->len) { - s->size = darg->layout->pos + darg->layout->len; - } - } - - psi_sort_struct_args(s); - - return 1; -} - -static const char * const abi_ccs[] = { - "default", /* \ */ - "extern", /* > - all the same */ - "cdecl", /* / */ - "mscdecl", - "stdcall", - "fastcall", -}; -static inline int validate_decl_abi(PSI_Data *data, decl_abi *abi) { - size_t i; - - for (i = 0; i < sizeof(abi_ccs)/sizeof(char*); ++i) { - if (strcasecmp(abi->convention, abi_ccs[i])) { - return 1; - } - } - return 0; -} -static inline int validate_decl_func(PSI_Data *data, void *dl, decl *decl, decl_arg *func) -{ - struct psi_func_redir *redir; - - if (!strcmp(func->var->name, "dlsym")) { - data->error(func->token, PSI_WARNING, "Cannot dlsym dlsym (sic!)"); - return 0; - } - - if (!validate_decl_arg(data, func)) { - return 0; - } - for (redir = &psi_func_redirs[0]; redir->name; ++redir) { - if (!strcmp(func->var->name, redir->name)) { - decl->call.sym = redir->func; - } - } - if (!decl->call.sym) { -#ifndef RTLD_NEXT -# define RTLD_NEXT ((void *) -1l) -#endif - decl->call.sym = dlsym(dl ?: RTLD_NEXT, func->var->name); - if (!decl->call.sym) { - data->error(func->token, PSI_WARNING, - "Failed to locate symbol '%s': %s", - func->var->name, dlerror()); - } - } - return 1; -} - -static inline int validate_decl(PSI_Data *data, void *dl, decl *decl) { - if (!validate_decl_abi(data, decl->abi)) { - data->error(decl->abi->token, PSI_WARNING, - "Invalid calling convention: '%s'", decl->abi->token->text); - return 0; - } - if (!validate_decl_func(data, dl, decl, decl->func)) { - return 0; - } - if (decl->args) { - size_t i; - - for (i = 0; i < decl->args->count; ++i) { - if (!validate_decl_arg(data, decl->args->args[i])) { - return 0; - } - } - } - return 1; -} -static inline decl_arg *locate_decl_var_arg(decl_var *var, decl_args *args, decl_arg *func) { - size_t i; - - for (i = 0; i < args->count; ++i) { - decl_arg *arg = args->args[i]; - - if (!strcmp(var->name, arg->var->name)) { - ZEND_ASSERT(!var->arg || var->arg == arg); - return var->arg = arg; - } - } - if (func && !strcmp(var->name, func->var->name)) { - return var->arg = func; - } - - return NULL; -} -static inline decl_arg *locate_struct_member(decl_struct *s, decl_var *var) { - if (s->args) { - return locate_decl_var_arg(var, s->args, NULL); - } - - return NULL; -} -static inline constant *locate_num_exp_constant(num_exp *exp, constants *consts) { - size_t i; - - for (i = 0; i < consts->count; ++i) { - constant *cnst = consts->list[i]; - - if (!strcmp(cnst->name, exp->u.numb)) { - free(exp->u.numb); - return exp->u.cnst = cnst; - } - } - - return NULL; -} -static inline int validate_num_exp(PSI_Data *data, decl_args *dargs, decl_arg *func, num_exp *exp) { - if (exp->operand) { - switch (exp->operator) { - case PSI_T_PLUS: - exp->calculator = psi_calc_add; - break; - case PSI_T_MINUS: - exp->calculator = psi_calc_sub; - break; - case PSI_T_ASTERISK: - exp->calculator = psi_calc_mul; - break; - case PSI_T_SLASH: - exp->calculator = psi_calc_div; - break; - EMPTY_SWITCH_DEFAULT_CASE(); - } - if (!validate_num_exp(data, dargs, func, exp->operand)) { - return 0; - } - } - switch (exp->t) { - case PSI_T_NAME: - if (!locate_decl_var_arg(exp->u.dvar, dargs, func)) { - data->error(exp->token, PSI_WARNING, "Unknown variable '%s' in numeric expression", - exp->u.dvar->name); - return 0; - } - return 1; - case PSI_T_NSNAME: - if (!locate_num_exp_constant(exp, data->consts)) { - data->error(exp->token, PSI_WARNING, "Unknown constant '%s' in numeric expression", - exp->u.numb); - return 0; - } - return 1; - case PSI_T_NUMBER: - return 1; - default: - return 0; - } -} -static inline int validate_set_value_handler(set_value *set) { - switch (set->func->type) { - case PSI_T_TO_BOOL: - set->func->handler = psi_to_bool; - break; - case PSI_T_TO_INT: - set->func->handler = psi_to_int; - break; - case PSI_T_TO_FLOAT: - set->func->handler = psi_to_double; - break; - case PSI_T_TO_STRING: - set->func->handler = psi_to_string; - break; - case PSI_T_TO_ARRAY: - set->func->handler = psi_to_array; - break; - case PSI_T_TO_OBJECT: - set->func->handler = psi_to_object; - break; - case PSI_T_VOID: - set->func->handler = psi_to_void; - break; - case PSI_T_ELLIPSIS: - if (set->outer.set && set->outer.set->func->type == PSI_T_TO_ARRAY) { - set->func->handler = psi_to_recursive; - set->inner = set->outer.set->inner; - set->count = set->outer.set->count; - break; - } - /* no break */ - default: - return 0; - } - return 1; -} -static inline void decl_var_arg_v(decl_args *args, va_list argp) { - int argc; - decl_arg **argv; - - memset(args, 0, sizeof(*args)); - - while ((argc = va_arg(argp, int))) { - argv = va_arg(argp, decl_arg **); - while (argc--) { - add_decl_arg(args, *argv++); - } - } -} -static inline int validate_set_value_ex(PSI_Data *data, set_value *set, decl_arg *ref, decl_args *ref_list) { - size_t i; - decl_type *ref_type; - decl_var *set_var = set->vars->vars[0]; - - if (!validate_set_value_handler(set)) { - data->error(set->func->token, PSI_WARNING, "Invalid cast '%s' in `set` statement", set->func->name); - return 0; - } - - for (i = 0; i < set->vars->count; ++i) { - decl_var *svar = set->vars->vars[i]; - if (!svar->arg && !locate_decl_var_arg(svar, ref_list, NULL)) { - data->error(svar->token, PSI_WARNING, "Unknown variable '%s' in `set` statement", svar->name); - return 0; - } - } - - if (!ref) { - ref = set_var->arg; - } - ref_type = real_decl_type(ref->type); - - if (set->count) { - int is_to_array = (set->func->type == PSI_T_TO_ARRAY); - int is_pointer_to_struct = (ref_type->type == PSI_T_STRUCT && ref->var->pointer_level); - - if (!is_to_array && !is_pointer_to_struct) { - data->error(set->func->token, E_WARNING, "Inner `set` statement casts only work with " - "to_array() casts on structs or pointers: %s(%s...", set->func->name, set->vars->vars[0]->name); - return 0; - } - } - if (set->num) { - if (!validate_num_exp(data, ref_list, ref, set->num)) { - return 0; - } - } - - if (ref_type->type == PSI_T_STRUCT) { - /* to_array(struct, to_...) */ - if (!set->outer.set || set->outer.set->inner != set->inner) { - for (i = 0; i < set->count; ++i) { - decl_var *sub_var = set->inner[i]->vars->vars[0]; - decl_arg *sub_ref = locate_struct_member(ref_type->strct, sub_var); - - if (sub_ref) { - if (!validate_set_value_ex(data, set->inner[i], sub_ref, ref_type->strct->args)) { - return 0; - } - } - } - } - } else if (set->count == 1) { - /* to_array(ptr, to_string(*ptr)) */ - decl_var *sub_var = set->inner[0]->vars->vars[0]; - decl_arg *sub_ref = locate_decl_var_arg(sub_var, ref_list, ref); - - if (sub_ref) { - if (strcmp(sub_var->name, set_var->name)) { - data->error(sub_var->token, E_WARNING, "Inner `set` statement casts on pointers must reference the same variable"); - return 0; - } - if (!validate_set_value_ex(data, set->inner[0], sub_ref, ref_list)) { - return 0; - } - } - } else if (set->count > 1) { - data->error(set->func->token, E_WARNING, "Inner `set` statement casts on pointers may only occur once"); - return 0; - } - - return 1; -} -static inline int validate_set_value(PSI_Data *data, set_value *set, ...) { - va_list argp; - decl_args args = {0}; - int check; - - va_start(argp, set); - decl_var_arg_v(&args, argp); - va_end(argp); - - check = validate_set_value_ex(data, set, NULL, &args); - if (args.args) { - free(args.args); - } - return check; -} -static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) { - if (decls) { - size_t i; - - for (i = 0; i < decls->count; ++i) { - if (!strcmp(decls->list[i]->func->var->name, ret->set->vars->vars[0]->name)) { - ret->decl = decls->list[i]->func; - return decls->list[i]; - } - } - } - - return NULL; -} -static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) { - return_stmt *ret; - - /* we must have exactly one ret stmt delcaring the native func to call */ - /* and which type cast to apply */ - if (impl->stmts->ret.count != 1) { - if (impl->stmts->ret.count > 1) { - data->error(impl->stmts->ret.list[1]->token, PSI_WARNING, - "Too many `return` statements for implmentation %s;" - " found %zu, exactly one is needed", - impl->func->name, impl->stmts->ret.count); - } else { - data->error(impl->func->token, PSI_WARNING, - "Missing `return` statement for implementation %s", - impl->func->name); - } - return 0; - } - - ret = impl->stmts->ret.list[0]; - - if (!(impl->decl = locate_impl_decl(data->decls, ret))) { - data->error(ret->token, PSI_WARNING, - "Missing declaration '%s' for `return` statment for implementation %s", - ret->set->vars->vars[0]->name, impl->func->name); - return 0; - } - - if (!validate_set_value(data, ret->set, 1, &ret->decl, impl->decl->args ? (int) impl->decl->args->count : 0, impl->decl->args ? impl->decl->args->args : NULL, 0)) { - return 0; - } - - impl->decl->impl = impl; - - return 1; -} - -static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) { - size_t i, j; - /* we can have multiple let stmts */ - - /* check that we have a decl arg for every let stmt */ - for (i = 0; i < impl->stmts->let.count; ++i) { - let_stmt *let = impl->stmts->let.list[i]; - decl_var *let_var; - int check = 0; - - if (let->val && let->val->kind == PSI_LET_TMP) { - let_var = let->val->data.var; - } else { - let_var = let->var; - } - - if (!locate_decl_var_arg(let_var, impl->decl->args, impl->decl->func)) { - data->error(let_var->token, PSI_WARNING, "Unknown variable '%s' in `let` statement" - " of implementation '%s'", let_var->name, impl->func->name); - return 0; - } - - switch (let->val->kind) { - case PSI_LET_NULL: - break; - case PSI_LET_TMP: - /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */ - /* e.g. let foo = *bar; */ - let->var->pointer_level = let->val->data.var->pointer_level; - let->var->arg = init_decl_arg( - init_decl_type( - real_decl_type(let->val->data.var->arg->type)->type, - real_decl_type(let->val->data.var->arg->type)->name), - init_decl_var( - let->var->name, - let->var->pointer_level, - let->var->array_size)); - break; - case PSI_LET_NUMEXP: - if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.num)) { - return 0; - } - break; - case PSI_LET_CALLOC: - if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.alloc->nmemb)) { - return 0; - } - if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.alloc->size)) { - return 0; - } - break; - case PSI_LET_FUNC: - if (impl->func->args) { - for (j = 0; j < impl->func->args->count; ++j) { - impl_arg *iarg = impl->func->args->args[j]; - - if (!strcmp(let->val->data.func->var->name, iarg->var->name)) { - let->val->data.func->arg = iarg; - check = 1; - break; - } - } - } - if (!check) { - data->error(let->var->token, PSI_WARNING, "Unknown value '$%s' of `let` statement" - " for variable '%s' of implementation '%s'", - let->val->data.func->var->name, let->var->name, impl->func->name); - return 0; - } - break; - } - } - - /* check that we have a let stmt for every decl arg */ - if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) { - decl_arg *darg = impl->decl->args->args[i]; - int check = 0; - - for (j = 0; j < impl->stmts->let.count; ++j) { - let_stmt *let = impl->stmts->let.list[j]; - - if (!strcmp(let->var->name, darg->var->name)) { - darg->let = let; - check = 1; - break; - } - } - if (!check) { - data->error(impl->func->token, PSI_WARNING, - "Missing `let` statement for arg '%s %.*s%s'" - " of declaration '%s' for implementation '%s'", - darg->type->name, (int) darg->var->pointer_level, "*****", - darg->var->name, impl->decl->func->var->name, impl->func->name); - return 0; - } - } - - return 1; -} -static inline int validate_impl_set_stmts(PSI_Data *data, impl *impl) { - size_t i, j, k; - /* we can have any count of set stmts; processing out vars */ - /* check that set stmts reference known variables */ - for (i = 0; i < impl->stmts->set.count; ++i) { - set_stmt *set = impl->stmts->set.list[i]; - int check = 0; - - if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) { - impl_arg *iarg = impl->func->args->args[j]; - - if (!strcmp(set->var->name, iarg->var->name)) { - set->arg = iarg; - check = 1; - break; - } - } - if (!check) { - data->error(set->var->token, PSI_WARNING, "Unknown variable '$%s' of `set` statement" - " of implementation '%s'", - set->var->name, impl->func->name); - return 0; - } - - for (j = 0; j < set->val->vars->count; ++j) { - decl_var *set_var = set->val->vars->vars[j]; - - check = 0; - if (impl->decl->args) { - for (k = 0; k < impl->decl->args->count; ++k) { - decl_arg *set_arg = impl->decl->args->args[k]; - - if (!strcmp(set_var->name, set_arg->var->name)) { - check = 1; - set_var->arg = set_arg; - if (!validate_set_value(data, set->val, 1, &set_arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) { - return 0; - } - break; - } - } - } - if (!check) { - for (k = 0; k < impl->stmts->let.count; ++k) { - let_stmt *let = impl->stmts->let.list[k]; - - /* check temp vars */ - if (let->val && let->val->kind == PSI_LET_TMP) { - if (!strcmp(set_var->name, let->var->name)) { - check = 1; - set_var->arg = let->var->arg; - if (!validate_set_value(data, set->val, 1, &set_var->arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) { - return 0; - } - break; - } - } - } - } - - if (!check) { - data->error(set_var->token, PSI_WARNING, "Unknown value '%s' of `set` statement" - " for variable '$%s' of implementation '%s'", - set_var->name, set->arg->var->name, impl->func->name); - return 0; - } - } - } - return 1; -} -static inline decl *locate_free_decl(decls *decls, free_call *f) { - if (decls) { - size_t i; - - for (i = 0; i < decls->count; ++i) { - if (!strcmp(decls->list[i]->func->var->name, f->func)) { - f->decl = decls->list[i]; - return decls->list[i]; - } - } - } - - return NULL; -} -static inline int validate_impl_free_stmts(PSI_Data *data, impl *impl) { - size_t i, j, k, l; - /* we can have any count of free stmts; freeing any out vars */ - for (i = 0; i < impl->stmts->fre.count; ++i) { - free_stmt *fre = impl->stmts->fre.list[i]; - - for (j = 0; j < fre->calls->count; ++j) { - free_call *free_call = fre->calls->list[j]; - - /* first find the decl of the free func */ - if (!locate_free_decl(data->decls, free_call)) { - data->error(free_call->token, PSI_WARNING, - "Missing declaration '%s' in `free` statement" - " of implementation '%s'", - free_call->func, impl->func->name); - return 0; - } - - - - /* now check for known vars */ - for (l = 0; l < free_call->vars->count; ++l) { - int check = 0; - decl_var *free_var = free_call->vars->vars[l]; - - if (!strcmp(free_var->name, impl->decl->func->var->name)) { - check = 1; - free_var->arg = impl->decl->func; - } else if (impl->decl->args) { - for (k = 0; k < impl->decl->args->count; ++k) { - decl_arg *free_arg = impl->decl->args->args[k]; - - if (!strcmp(free_var->name, free_arg->var->name)) { - check = 1; - free_var->arg = free_arg; - break; - } - } - } - - if (!check) { - data->error(free_var->token, PSI_WARNING, - "Unknown variable '%s' of `free` statement" - " of implementation '%s'", - free_var->name, impl->func->name); - return 0; - } - } - } - } - return 1; -} -static inline int validate_impl_stmts(PSI_Data *data, impl *impl) { - if (!impl->stmts) { - data->error(impl->func->token, PSI_WARNING, - "Missing body for implementation %s!", - impl->func->name); - return 0; - } - - if (!validate_impl_ret_stmt(data, impl)) { - return 0; - } - - if (!validate_impl_let_stmts(data, impl)) { - return 0; - } - if (!validate_impl_set_stmts(data, impl)) { - return 0; - } - if (!validate_impl_free_stmts(data, impl)) { - return 0; - } - - return 1; -} - -static inline int validate_impl_args(PSI_Data *data, impl *impl) { - int def = 0; - size_t i; - - for (i = 0; i < impl->func->args->count; ++i) { - impl_arg *iarg = impl->func->args->args[i]; - - if (iarg->def) { - def = 1; - } else if (def) { - data->error(impl->func->token, PSI_WARNING, - "Non-optional argument %zu '$%s' of implementation '%s'" - " follows optional argument", - i+1, iarg->var->name, impl->func->name); - return 0; - } - } - - return 1; -} -static inline int validate_impl(PSI_Data *data, impl *impl) { - if (!validate_impl_args(data, impl)) { - return 0; - } - return validate_impl_stmts(data, impl); -} PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error) { - size_t i; PSI_Data T; struct psi_predef_type *predef_type; struct psi_predef_const *predef_const; @@ -980,37 +137,7 @@ PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErr predef_decl = farg; } - for (i = 0; i < T.defs->count; ++i) { - decl_typedef *def = T.defs->list[i]; - - if (validate_decl_typedef(&T, def)) { - C->defs = add_decl_typedef(C->defs, def); - } - } - - for (i = 0; i < T.consts->count; ++i) { - constant *constant = T.consts->list[i]; - - if (validate_constant(&T, constant)) { - C->consts = add_constant(C->consts, constant); - } - } - - for (i = 0; i < T.structs->count; ++i) { - decl_struct *dstruct = T.structs->list[i]; - - if (validate_decl_struct(&T, dstruct)) { - C->structs = add_decl_struct(C->structs, dstruct); - } - } - - for (i = 0; i < T.decls->count; ++i) { - decl *decl = T.decls->list[i]; - - if (validate_decl(&T, NULL, decl)) { - C->decls = add_decl(C->decls, decl); - } - } + PSI_ContextValidatePredef(C, &T); C->count = 1; C->data = malloc(sizeof(*C->data)); @@ -1019,71 +146,6 @@ PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErr return C; } -int PSI_ContextValidate(PSI_Context *C, PSI_Parser *P) -{ - PSI_Data *D; - void *dlopened = NULL; - size_t count = C->count++; - - C->data = realloc(C->data, C->count * sizeof(*C->data)); - D = PSI_DataExchange(&C->data[count], PSI_DATA(P)); - - if (D->defs) { - size_t i; - - for (i = 0; i < D->defs->count; ++i) { - if (validate_decl_typedef(PSI_DATA(C), D->defs->list[i])) { - C->defs = add_decl_typedef(C->defs, D->defs->list[i]); - } - } - } - if (D->structs) { - size_t i; - - for (i = 0; i < D->structs->count; ++i) { - if (validate_decl_struct(PSI_DATA(C), D->structs->list[i])) { - C->structs = add_decl_struct(C->structs, D->structs->list[i]); - } - } - } - if (D->consts) { - size_t i; - - for (i = 0; i < D->consts->count; ++i) { - if (validate_constant(PSI_DATA(C), D->consts->list[i])) { - C->consts = add_constant(C->consts, D->consts->list[i]); - } - } - } - - if (!validate_lib(D, &dlopened)) { - return 0; - } - - add_decl_lib(&C->psi.libs, dlopened); - - if (D->decls) { - size_t i; - - for (i = 0; i < D->decls->count; ++i) { - if (validate_decl(PSI_DATA(C), dlopened, D->decls->list[i])) { - C->decls = add_decl(C->decls, D->decls->list[i]); - } - } - } - if (D->impls) { - size_t i; - - for (i = 0; i < D->impls->count; ++i) { - if (validate_impl(PSI_DATA(C), D->impls->list[i])) { - C->impls = add_impl(C->impls, D->impls->list[i]); - } - } - } - - return 1; -} - static int psi_select_dirent(const struct dirent *entry) { #ifndef FNM_CASEFOLD @@ -1195,292 +257,6 @@ void PSI_ContextCall(PSI_Context *C, decl_callinfo *decl_call, impl_vararg *va) C->ops->call(C, decl_call, va); } -static inline void dump_decl_type(int fd, decl_type *t) { - const char *pre; - - switch (t->type) { - case PSI_T_STRUCT: - pre = "struct "; - break; - default: - pre = ""; - } - dprintf(fd, "%s%s", pre, t->name); -} -static inline void dump_decl_var(int fd, decl_var *v) { - dprintf(fd, "%.*s%s", v->pointer_level-!!v->array_size, "**********", v->name); - if (v->array_size) { - dprintf(fd, "[%u]", v->array_size); - } -} -static inline void dump_decl_arg(int fd, decl_arg *a) { - dump_decl_type(fd, a->type); - dprintf(fd, " "); - dump_decl_var(fd, a->var); -} -static inline void dump_level(int fd, unsigned level) { - dprintf(fd, "%.*s", level, "\t\t\t\t\t\t\t\t\t"); -} -static inline void dump_num_exp(int fd, num_exp *exp) { - while (exp) { - switch (exp->t) { - case PSI_T_NUMBER: - dprintf(fd, "%s", exp->u.numb); - break; - case PSI_T_NSNAME: - dprintf(fd, "%s", exp->u.cnst->name); - break; - case PSI_T_NAME: - dump_decl_var(fd, exp->u.dvar); - break; - EMPTY_SWITCH_DEFAULT_CASE(); - } - if (exp->operand) { - char op; - - switch (exp->operator) { - case PSI_T_PLUS: op = '+'; break; - case PSI_T_MINUS: op = '-'; break; - case PSI_T_ASTERISK:op = '*'; break; - case PSI_T_SLASH: op = '/'; break; - EMPTY_SWITCH_DEFAULT_CASE(); - } - dprintf(fd, " %c ", op); - } - exp = exp->operand; - } -} - -static inline void dump_impl_set_value(int fd, set_value *set, unsigned level, int last) { - size_t i; - - if (level > 1) { - /* only if not directly after `set ...` */ - dump_level(fd, level); - } - - if (set->func->type == PSI_T_ELLIPSIS) { - dprintf(fd, "%s(", set->outer.set->func->name); - } else { - dprintf(fd, "%s(", set->func->name); - } - - for (i = 0; i < set->vars->count; ++i) { - decl_var *svar = set->vars->vars[i]; - if (i) { - dprintf(fd, ", "); - } - dump_decl_var(fd, svar); - } - - if (set->func->type == PSI_T_ELLIPSIS) { - dprintf(fd, ", ..."); - } - if (set->num) { - dprintf(fd, ", "); - dump_num_exp(fd, set->num); - } - if (set->inner && set->func->type != PSI_T_ELLIPSIS) { - dprintf(fd, ",\n"); - for (i = 0; i < set->count; ++i) { - dump_impl_set_value(fd, set->inner[i], level+1, i == (set->count - 1)); - } - /* only if inner stmts, i.e. with new lines, were dumped */ - dump_level(fd, level); - } - if (level > 1) { - dprintf(fd, ")%s\n", last ? "" : ","); - } else { - dprintf(fd, ");\n"); - } -} -void PSI_ContextDump(PSI_Context *C, int fd) -{ - size_t i, j, k, l; - -#ifdef HAVE_LIBJIT - if (C->ops == PSI_Libjit()) { - dprintf(fd, "// psi.engine=jit\n"); - } -#endif -#ifdef HAVE_LIBFFI - if (C->ops == PSI_Libffi()) { - dprintf(fd, "// psi.engine=ffi\n"); - } -#endif - dprintf(fd, "\n"); - - if (C->defs) { - for (i = 0; i < C->defs->count; ++i) { - decl_typedef *tdef = C->defs->list[i]; - - dprintf(fd, "typedef "); - dump_decl_type(fd, tdef->type); - dprintf(fd, " %s%s;\n", tdef->type->type == PSI_T_POINTER ? "*":"", - tdef->alias); - } - dprintf(fd, "\n"); - } - - if (C->structs) { - for (i = 0; i < C->structs->count; ++i) { - decl_struct *strct = C->structs->list[i]; - - dprintf(fd, "struct %s::(%zu)", strct->name, strct->size); - if (strct->args && strct->args->count) { - dprintf(fd, " {\n"); - for (j = 0; j < strct->args->count; ++j) { - decl_arg *sarg = strct->args->args[j]; - - dprintf(fd, "\t"); - dump_decl_arg(fd, sarg); - dprintf(fd, "::(%zu, %zu);\n", sarg->layout->pos, sarg->layout->len); - } - dprintf(fd, "}"); - } else { - dprintf(fd, ";"); - } - dprintf(fd, "\n"); - - } - dprintf(fd, "\n"); - } - if (C->consts) { - for (i = 0; i < C->consts->count; ++i) { - constant *cnst = C->consts->list[i]; - - dprintf(fd, "const %s %s = ", cnst->type->name, cnst->name); - if (cnst->val->type == PSI_T_QUOTED_STRING) { - dprintf(fd, "\"%s\";\n", cnst->val->text); - } else { - dprintf(fd, "%s;\n", cnst->val->text); - } - } - dprintf(fd, "\n"); - } - if (C->decls) { - for (i = 0; i < C->decls->count; ++i) { - decl *decl = C->decls->list[i]; - - dprintf(fd, "%s ", decl->abi->convention); - dump_decl_arg(fd, decl->func); - dprintf(fd, "("); - if (decl->args) { - for (j = 0; j < decl->args->count; ++j) { - if (j) { - dprintf(fd, ", "); - } - dump_decl_arg(fd, decl->args->args[j]); - } - if (decl->args->varargs) { - dprintf(fd, ", ..."); - } - } - dprintf(fd, ");\n"); - } - dprintf(fd, "\n"); - } - if (C->impls) { - for (i = 0; i < C->impls->count; ++i) { - impl *impl = C->impls->list[i]; - - dprintf(fd, "function %s(", impl->func->name); - if (impl->func->args) { - for (j = 0; j < impl->func->args->count; ++j) { - impl_arg *iarg = impl->func->args->args[j]; - - dprintf(fd, "%s%s %s$%s", - j ? ", " : "", - iarg->type->name, - iarg->var->reference ? "&" : "", - iarg->var->name); - if (iarg->def) { - dprintf(fd, " = %s", iarg->def->text); - } - } - if (impl->func->args->vararg.name) { - impl_arg *vararg = impl->func->args->vararg.name; - - dprintf(fd, ", %s %s...$%s", - vararg->type->name, - vararg->var->reference ? "&" : "", - vararg->var->name); - } - } - dprintf(fd, ") : %s%s {\n", - impl->func->return_reference ? "&":"", - impl->func->return_type->name); - if (impl->stmts) { - for (j = 0; j < impl->stmts->let.count; ++j) { - let_stmt *let = impl->stmts->let.list[j]; - - dprintf(fd, "\tlet %s", let->var->name); - if (let->val) { - dprintf(fd, " = %s", let->val->flags.one.is_reference ? "&" : ""); - switch (let->val->kind) { - case PSI_LET_NULL: - dprintf(fd, "NULL"); - break; - case PSI_LET_TMP: - dump_decl_var(fd, let->val->data.var); - break; - case PSI_LET_CALLOC: - dprintf(fd, "calloc("); - dump_num_exp(fd, let->val->data.alloc->nmemb); - dprintf(fd, ", "); - dump_num_exp(fd, let->val->data.alloc->size); - dprintf(fd, ")"); - break; - case PSI_LET_FUNC: - dprintf(fd, "%s($%s)", let->val->data.func->name, - let->val->data.func->var->name); - break; - case PSI_LET_NUMEXP: - dump_num_exp(fd, let->val->data.num); - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - dprintf(fd, ";\n"); - } - } - for (j = 0; j < impl->stmts->ret.count; ++j) { - return_stmt *ret = impl->stmts->ret.list[j]; - - dprintf(fd, "\treturn "); - dump_impl_set_value(fd, ret->set, 1, 0); - } - for (j = 0; j < impl->stmts->set.count; ++j) { - set_stmt *set = impl->stmts->set.list[j]; - - dprintf(fd, "\tset $%s = ", set->var->name); - dump_impl_set_value(fd, set->val, 1, 0); - } - for (j = 0; j < impl->stmts->fre.count; ++j) { - free_stmt *fre = impl->stmts->fre.list[j]; - - dprintf(fd, "\tfree "); - for (k = 0; k < fre->calls->count; ++k) { - free_call *call = fre->calls->list[k]; - - if (k) { - dprintf(fd, ", "); - } - dprintf(fd, "%s(", call->func); - for (l = 0; l < call->vars->count; ++l) { - decl_var *fvar = call->vars->vars[l]; - - dump_decl_var(fd, fvar); - } - dprintf(fd, ");\n"); - } - } - } - dprintf(fd, "}\n"); - } - dprintf(fd, "\n"); - } -} void PSI_ContextDtor(PSI_Context *C) { diff --git a/src/context.h b/src/context.h index c8416a5..386304b 100644 --- a/src/context.h +++ b/src/context.h @@ -29,6 +29,7 @@ struct PSI_Context { PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error); void PSI_ContextBuild(PSI_Context *C, const char *path); int PSI_ContextValidate(PSI_Context *C, PSI_Parser *P); +void PSI_ContextValidatePredef(PSI_Context *C, PSI_Data *D); zend_function_entry *PSI_ContextCompile(PSI_Context *C); void PSI_ContextCall(PSI_Context *C, decl_callinfo *decl_call, impl_vararg *va); void PSI_ContextDump(PSI_Context *C, int fd); diff --git a/src/context_dump.c b/src/context_dump.c new file mode 100644 index 0000000..93b8f32 --- /dev/null +++ b/src/context_dump.c @@ -0,0 +1,391 @@ +#include "php.h" +#include "php_psi.h" + +#include "libjit.h" +#include "libffi.h" + +static inline void dump_decl_type(int fd, decl_type *t) { + const char *pre; + + switch (t->type) { + case PSI_T_STRUCT: + pre = "struct "; + break; + default: + pre = ""; + } + dprintf(fd, "%s%s", pre, t->name); +} + +static inline void dump_decl_var(int fd, decl_var *v) { + dprintf(fd, "%.*s%s", v->pointer_level-!!v->array_size, "**********", v->name); + if (v->array_size) { + dprintf(fd, "[%u]", v->array_size); + } +} + +static inline void dump_decl_arg(int fd, decl_arg *a) { + dump_decl_type(fd, a->type); + dprintf(fd, " "); + dump_decl_var(fd, a->var); +} + +static inline void dump_level(int fd, unsigned level) { + dprintf(fd, "%.*s", level > 10 ? 10 : level, "\t\t\t\t\t\t\t\t\t\t"); +} + +static inline void dump_num_exp(int fd, num_exp *exp) { + while (exp) { + switch (exp->t) { + case PSI_T_NUMBER: + dprintf(fd, "%s", exp->u.numb); + break; + case PSI_T_NSNAME: + dprintf(fd, "%s", exp->u.cnst->name); + break; + case PSI_T_NAME: + dump_decl_var(fd, exp->u.dvar); + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + if (exp->operand) { + char op; + + switch (exp->operator) { + case PSI_T_PLUS: op = '+'; break; + case PSI_T_MINUS: op = '-'; break; + case PSI_T_ASTERISK:op = '*'; break; + case PSI_T_SLASH: op = '/'; break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + dprintf(fd, " %c ", op); + } + exp = exp->operand; + } +} + +static inline void dump_impl_set_value(int fd, set_value *set, unsigned level, int last) { + size_t i; + + if (level > 1) { + /* only if not directly after `set ...` */ + dump_level(fd, level); + } + + if (set->func->type == PSI_T_ELLIPSIS) { + dprintf(fd, "%s(", set->outer.set->func->name); + } else { + dprintf(fd, "%s(", set->func->name); + } + + for (i = 0; i < set->vars->count; ++i) { + decl_var *svar = set->vars->vars[i]; + if (i) { + dprintf(fd, ", "); + } + dump_decl_var(fd, svar); + } + + if (set->func->type == PSI_T_ELLIPSIS) { + dprintf(fd, ", ..."); + } + if (set->num) { + dprintf(fd, ", "); + dump_num_exp(fd, set->num); + } + if (set->inner && set->func->type != PSI_T_ELLIPSIS) { + dprintf(fd, ",\n"); + for (i = 0; i < set->count; ++i) { + dump_impl_set_value(fd, set->inner[i], level+1, i == (set->count - 1)); + } + /* only if inner stmts, i.e. with new lines, were dumped */ + dump_level(fd, level); + } + if (level > 1) { + dprintf(fd, ")%s\n", last ? "" : ","); + } else { + dprintf(fd, ");"); + } +} + +static inline void dump_typedef(int fd, decl_typedef *tdef) { + dprintf(fd, "typedef "); + dump_decl_type(fd, tdef->type); + dprintf(fd, " %s%s;", tdef->type->type == PSI_T_POINTER ? "*":"", + tdef->alias); +} + +static inline void dump_typedefs(int fd, decl_typedefs *defs) { + size_t i; + + for (i = 0; i < defs->count; ++i) { + decl_typedef *tdef = defs->list[i]; + + dump_typedef(fd, tdef); + dprintf(fd, "\n"); + } +} + +static inline void dump_struct(int fd, decl_struct *strct) { + size_t j; + + dprintf(fd, "struct %s::(%zu)", strct->name, strct->size); + if (strct->args && strct->args->count) { + dprintf(fd, " {\n"); + for (j = 0; j < strct->args->count; ++j) { + decl_arg *sarg = strct->args->args[j]; + + dprintf(fd, "\t"); + dump_decl_arg(fd, sarg); + dprintf(fd, "::(%zu, %zu);\n", sarg->layout->pos, sarg->layout->len); + } + dprintf(fd, "}"); + } else { + dprintf(fd, ";"); + } +} +static inline void dump_structs(int fd, decl_structs *structs) { + size_t i; + + for (i = 0; i < structs->count; ++i) { + decl_struct *strct = structs->list[i]; + + dump_struct(fd, strct); + dprintf(fd, "\n"); + } +} + +static inline void dump_constant(int fd, constant *cnst) { + dprintf(fd, "const %s %s = ", cnst->type->name, cnst->name); + if (cnst->val->type == PSI_T_QUOTED_STRING) { + dprintf(fd, "\"%s\";", cnst->val->text); + } else { + dprintf(fd, "%s;", cnst->val->text); + } +} + +static inline void dump_constants(int fd, constants *consts) { + size_t i; + + for (i = 0; i < consts->count; ++i) { + constant *cnst = consts->list[i]; + + dump_constant(fd, cnst); + dprintf(fd, "\n"); + } +} + +static inline void dump_decl(int fd, decl *decl) { + size_t j; + + dprintf(fd, "%s ", decl->abi->convention); + dump_decl_arg(fd, decl->func); + dprintf(fd, "("); + if (decl->args) { + for (j = 0; j < decl->args->count; ++j) { + if (j) { + dprintf(fd, ", "); + } + dump_decl_arg(fd, decl->args->args[j]); + } + if (decl->args->varargs) { + dprintf(fd, ", ..."); + } + } + dprintf(fd, ");"); +} + +static inline void dump_decls(int fd, decls *decls) { + size_t i; + + for (i = 0; i < decls->count; ++i) { + decl *decl = decls->list[i]; + + dump_decl(fd, decl); + dprintf(fd, "\n"); + } +} + +static inline void dump_impl_func(int fd, impl_func *func) { + size_t j; + + dprintf(fd, "function %s(", func->name); + if (func->args) { + for (j = 0; j < func->args->count; ++j) { + impl_arg *iarg = func->args->args[j]; + + dprintf(fd, "%s%s %s$%s", + j ? ", " : "", + iarg->type->name, + iarg->var->reference ? "&" : "", + iarg->var->name); + if (iarg->def) { + dprintf(fd, " = %s", iarg->def->text); + } + } + if (func->args->vararg.name) { + impl_arg *vararg = func->args->vararg.name; + + dprintf(fd, ", %s %s...$%s", + vararg->type->name, + vararg->var->reference ? "&" : "", + vararg->var->name); + } + } + dprintf(fd, ") : %s%s", + func->return_reference ? "&":"", + func->return_type->name); +} + +static inline void dump_impl_let_stmt(int fd, let_stmt *let) { + dprintf(fd, "\tlet %s", let->var->name); + if (let->val) { + dprintf(fd, " = %s", let->val->flags.one.is_reference ? "&" : ""); + switch (let->val->kind) { + case PSI_LET_NULL: + dprintf(fd, "NULL"); + break; + case PSI_LET_TMP: + dump_decl_var(fd, let->val->data.var); + break; + case PSI_LET_CALLOC: + dprintf(fd, "calloc("); + dump_num_exp(fd, let->val->data.alloc->nmemb); + dprintf(fd, ", "); + dump_num_exp(fd, let->val->data.alloc->size); + dprintf(fd, ")"); + break; + case PSI_LET_FUNC: + dprintf(fd, "%s($%s)", let->val->data.func->name, + let->val->data.func->var->name); + break; + case PSI_LET_NUMEXP: + dump_num_exp(fd, let->val->data.num); + break; + + EMPTY_SWITCH_DEFAULT_CASE(); + } + dprintf(fd, ";"); + } +} + +static inline void dump_impl_return_stmt(int fd, return_stmt *ret) { + dprintf(fd, "\treturn "); + dump_impl_set_value(fd, ret->set, 1, 0); +} + +static inline void dump_impl_set_stmt(int fd, set_stmt *set) { + dprintf(fd, "\tset $%s = ", set->var->name); + dump_impl_set_value(fd, set->val, 1, 0); +} + +static inline void dump_impl_free_call(int fd, free_call *call) { + size_t l; + + dprintf(fd, "%s(", call->func); + for (l = 0; l < call->vars->count; ++l) { + decl_var *fvar = call->vars->vars[l]; + + dump_decl_var(fd, fvar); + } + dprintf(fd, ");"); +} + +static inline void dump_impl_free_stmt(int fd, free_stmt *fre) { + size_t k; + + dprintf(fd, "\tfree "); + for (k = 0; k < fre->calls->count; ++k) { + free_call *call = fre->calls->list[k]; + + if (k) { + dprintf(fd, ", "); + } + dump_impl_free_call(fd, call); + dprintf(fd, "\n"); + } +} +static inline void dump_impl_stmts(int fd, impl_stmts *stmts) { + size_t j; + + for (j = 0; j < stmts->let.count; ++j) { + let_stmt *let = stmts->let.list[j]; + dump_impl_let_stmt(fd, let); + dprintf(fd, "\n"); + } + for (j = 0; j < stmts->ret.count; ++j) { + return_stmt *ret = stmts->ret.list[j]; + dump_impl_return_stmt(fd, ret); + dprintf(fd, "\n"); + } + for (j = 0; j < stmts->set.count; ++j) { + set_stmt *set = stmts->set.list[j]; + + dump_impl_set_stmt(fd, set); + dprintf(fd, "\n"); + } + for (j = 0; j < stmts->fre.count; ++j) { + free_stmt *fre = stmts->fre.list[j]; + + dump_impl_free_stmt(fd, fre); + dprintf(fd, "\n"); + } +} + +static inline void dump_impl(int fd, impl *impl) { + + dump_impl_func(fd, impl->func); + dprintf(fd, " {\n"); + if (impl->stmts) { + dump_impl_stmts(fd, impl->stmts); + } + dprintf(fd, "}"); +} + +static inline void dump_impls(int fd, impls *impls) { + size_t i; + + for (i = 0; i < impls->count; ++i) { + impl *impl = impls->list[i]; + + dump_impl(fd, impl); + dprintf(fd, "\n"); + } +} + +void PSI_ContextDump(PSI_Context *C, int fd) +{ +#ifdef HAVE_LIBJIT + if (C->ops == PSI_Libjit()) { + dprintf(fd, "// psi.engine=jit\n"); + } +#endif +#ifdef HAVE_LIBFFI + if (C->ops == PSI_Libffi()) { + dprintf(fd, "// psi.engine=ffi\n"); + } +#endif + dprintf(fd, "\n"); + + if (C->defs) { + dump_typedefs(fd, C->defs); + dprintf(fd, "\n"); + } + + if (C->structs) { + dump_structs(fd, C->structs); + dprintf(fd, "\n"); + } + if (C->consts) { + dump_constants(fd, C->consts); + dprintf(fd, "\n"); + } + if (C->decls) { + dump_decls(fd, C->decls); + dprintf(fd, "\n"); + } + if (C->impls) { + dump_impls(fd, C->impls); + dprintf(fd, "\n"); + } +} diff --git a/src/context_validate.c b/src/context_validate.c new file mode 100644 index 0000000..da760c6 --- /dev/null +++ b/src/context_validate.c @@ -0,0 +1,957 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" + +#include +#include + +#include "php_psi.h" +#include "php_psi_stdinc.h" +#include "php_psi_stdtypes.h" +#include "php_psi_macros.h" +#include "php_psi_redirs.h" + +#include "calc.h" +#include "marshal.h" +#include "engine.h" + +static int validate_lib(PSI_Data *data, void **dlopened) { + char lib[MAXPATHLEN]; + const char *ptr = data->psi.file.ln; + size_t len; + + if (!ptr) { + /* FIXME: assume stdlib */ + return 1; + } else if (!strchr(ptr, '/')) { + len = snprintf(lib, MAXPATHLEN, "lib%s.%s", ptr, PHP_PSI_SHLIB_SUFFIX); + if (MAXPATHLEN == len) { + data->error(NULL, PSI_WARNING, "Library name too long: '%s'", ptr); + } + lib[len] = 0; + ptr = lib; + } + if (!(*dlopened = dlopen(ptr, RTLD_LAZY|RTLD_LOCAL))) { + data->error(NULL, PSI_WARNING, "Could not open library '%s': %s.", + data->psi.file.ln, dlerror()); + return 0; + } + return 1; +} + +static inline int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) { + size_t i; + struct psi_std_type *stdtyp; + + if (type->real) { + return 1; + } + for (i = 0; i < defs->count; ++i) { + decl_typedef *def = defs->list[i]; + + if (def->type->type != type->type && !strcmp(def->alias, type->name)) { + type->real = def->type; + return 1; + } + } + for (stdtyp = &psi_std_types[0]; stdtyp->type_tag; ++stdtyp) { + if (!strcmp(type->name, stdtyp->alias ?: stdtyp->type_name)) { + type->type = stdtyp->type_tag; + return 1; + } + } + + return 0; +} +static inline int locate_decl_type_struct(decl_structs *structs, decl_type *type) { + size_t i; + + if (type->strct) { + return 1; + } + for (i = 0; i < structs->count; ++i) { + if (!strcmp(structs->list[i]->name, type->name)) { + type->strct = structs->list[i]; + return 1; + } + } + return 0; +} + +static inline int validate_decl_type(PSI_Data *data, decl_type *type) { + switch (type->type) { + case PSI_T_CHAR: + case PSI_T_SHORT: + case PSI_T_INT: + case PSI_T_LONG: + case PSI_T_NAME: + if (!data->defs || !locate_decl_type_alias(data->defs, type)) { + return 0; + } + if (type->real) { + return validate_decl_type(data, type->real); + } + return 1; + case PSI_T_STRUCT: + if (!data->structs || !locate_decl_type_struct(data->structs, type)) { + return 0; + } + break; + } + return 1; +} +static inline int validate_decl_typedef(PSI_Data *data, decl_typedef *def) { + if (!validate_decl_type(data, def->type)) { + data->error(def->token, PSI_WARNING, + "Type '%s' cannot be aliased to %s'%s'", + def->type->name, def->type->type == PSI_T_STRUCT?"struct ":"",def->alias); + return 0; + } + /* FIXME: check def->alias */ + return 1; +} + +static inline int validate_constant(PSI_Data *data, constant *c) { + /* FIXME */ + return 1; +} + +static inline int validate_decl_arg(PSI_Data *data, decl_arg *arg) { + if (!validate_decl_type(data, arg->type)) { + data->error(arg->type->token, PSI_WARNING, + "Cannot use '%s'(%d) as type for decl var '%s'", + arg->type->name, arg->type->type, arg->var->name); + return 0; + } + return 1; +} + +static int psi_sort_struct_arg_cmp(const void *_a, const void *_b) { + decl_arg *a = *(decl_arg **)_a, *b = *(decl_arg **)_b; + + if (a->layout->pos == b->layout->pos) { + if (a->layout->len == b->layout->len) { + return 0; + } else if (a->layout->len > b->layout->len) { + return -1; + } else { + return 1; + } + } else if (a->layout->pos > b->layout->pos) { + return 1; + } else { + return -1; + } +} +static void psi_sort_struct_arg_swp(void *a, void *b) { + decl_arg **_a = a, **_b = b, *_c; + + _c = *_b; + *_b = *_a; + *_a = _c; +} +static inline void psi_sort_struct_args(decl_struct *s) { + zend_insert_sort(s->args->args, s->args->count, sizeof(*s->args->args), + psi_sort_struct_arg_cmp, psi_sort_struct_arg_swp); +} + +static inline int validate_decl_struct(PSI_Data *data, decl_struct *s) { + size_t i; + + for (i = 0; i < s->args->count; ++i) { + if (!validate_decl_arg(data, s->args->args[i])) { + return 0; + } + } + + for (i = 0; i < s->args->count; ++i) { + decl_arg *darg = s->args->args[i]; + + if (!validate_decl_arg(data, darg)) { + return 0; + } + + ZEND_ASSERT(!darg->var->arg || darg->var->arg == darg); + darg->var->arg = darg; + + if (darg->layout) { + size_t size; + + if (darg->var->array_size) { + size = psi_t_size(real_decl_type(darg->type)->type) * darg->var->array_size; + } else if (darg->var->pointer_level) { + size = psi_t_size(PSI_T_POINTER); + } else { + decl_type *real = real_decl_type(darg->type); + + if (real->type == PSI_T_STRUCT) { + size = real->strct->size; + } else { + size = psi_t_size(real->type); + } + } + if (darg->layout->len != size) { + data->error(darg->token, PSI_WARNING, + "Computed length %zu of %s.%s does not match" + " pre-defined length %zu of type '%s'", + darg->layout->len, s->name, darg->var->name, size, + darg->type->name); + return 0; + } + } else { + token_t t; + + if (darg->var->pointer_level && (!darg->var->array_size || darg->var->pointer_level == 1)) { + t = PSI_T_POINTER; + } else { + t = real_decl_type(darg->type)->type; + } + + if (i) { + decl_arg *last = s->args->args[i-1]; + darg->layout = init_decl_struct_layout( + psi_t_align(t, last->layout->pos + last->layout->len), + psi_t_size(t) * darg->var->array_size); + } else { + darg->layout = init_decl_struct_layout(0, psi_t_size(t)); + } + } + if (s->size < darg->layout->pos + darg->layout->len) { + s->size = darg->layout->pos + darg->layout->len; + } + } + + psi_sort_struct_args(s); + + return 1; +} + +static const char * const abi_ccs[] = { + "default", /* \ */ + "extern", /* > - all the same */ + "cdecl", /* / */ + "mscdecl", + "stdcall", + "fastcall", +}; +static inline int validate_decl_abi(PSI_Data *data, decl_abi *abi) { + size_t i; + + for (i = 0; i < sizeof(abi_ccs)/sizeof(char*); ++i) { + if (strcasecmp(abi->convention, abi_ccs[i])) { + return 1; + } + } + return 0; +} +static inline int validate_decl_func(PSI_Data *data, void *dl, decl *decl, decl_arg *func) +{ + struct psi_func_redir *redir; + + if (!strcmp(func->var->name, "dlsym")) { + data->error(func->token, PSI_WARNING, "Cannot dlsym dlsym (sic!)"); + return 0; + } + + if (!validate_decl_arg(data, func)) { + return 0; + } + for (redir = &psi_func_redirs[0]; redir->name; ++redir) { + if (!strcmp(func->var->name, redir->name)) { + decl->call.sym = redir->func; + } + } + if (!decl->call.sym) { +#ifndef RTLD_NEXT +# define RTLD_NEXT ((void *) -1l) +#endif + decl->call.sym = dlsym(dl ?: RTLD_NEXT, func->var->name); + if (!decl->call.sym) { + data->error(func->token, PSI_WARNING, + "Failed to locate symbol '%s': %s", + func->var->name, dlerror()); + } + } + return 1; +} + +static inline int validate_decl(PSI_Data *data, void *dl, decl *decl) { + if (!validate_decl_abi(data, decl->abi)) { + data->error(decl->abi->token, PSI_WARNING, + "Invalid calling convention: '%s'", decl->abi->token->text); + return 0; + } + if (!validate_decl_func(data, dl, decl, decl->func)) { + return 0; + } + if (decl->args) { + size_t i; + + for (i = 0; i < decl->args->count; ++i) { + if (!validate_decl_arg(data, decl->args->args[i])) { + return 0; + } + } + } + return 1; +} +static inline decl_arg *locate_decl_var_arg(decl_var *var, decl_args *args, decl_arg *func) { + size_t i; + + for (i = 0; i < args->count; ++i) { + decl_arg *arg = args->args[i]; + + if (!strcmp(var->name, arg->var->name)) { + ZEND_ASSERT(!var->arg || var->arg == arg); + return var->arg = arg; + } + } + if (func && !strcmp(var->name, func->var->name)) { + return var->arg = func; + } + + return NULL; +} +static inline decl_arg *locate_struct_member(decl_struct *s, decl_var *var) { + if (s->args) { + return locate_decl_var_arg(var, s->args, NULL); + } + + return NULL; +} +static inline constant *locate_num_exp_constant(num_exp *exp, constants *consts) { + size_t i; + + for (i = 0; i < consts->count; ++i) { + constant *cnst = consts->list[i]; + + if (!strcmp(cnst->name, exp->u.numb)) { + free(exp->u.numb); + return exp->u.cnst = cnst; + } + } + + return NULL; +} +static inline int validate_num_exp(PSI_Data *data, decl_args *dargs, decl_arg *func, num_exp *exp) { + if (exp->operand) { + switch (exp->operator) { + case PSI_T_PLUS: + exp->calculator = psi_calc_add; + break; + case PSI_T_MINUS: + exp->calculator = psi_calc_sub; + break; + case PSI_T_ASTERISK: + exp->calculator = psi_calc_mul; + break; + case PSI_T_SLASH: + exp->calculator = psi_calc_div; + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + if (!validate_num_exp(data, dargs, func, exp->operand)) { + return 0; + } + } + switch (exp->t) { + case PSI_T_NAME: + if (!locate_decl_var_arg(exp->u.dvar, dargs, func)) { + data->error(exp->token, PSI_WARNING, "Unknown variable '%s' in numeric expression", + exp->u.dvar->name); + return 0; + } + return 1; + case PSI_T_NSNAME: + if (!locate_num_exp_constant(exp, data->consts)) { + data->error(exp->token, PSI_WARNING, "Unknown constant '%s' in numeric expression", + exp->u.numb); + return 0; + } + return 1; + case PSI_T_NUMBER: + return 1; + default: + return 0; + } +} +static inline int validate_set_value_handler(set_value *set) { + switch (set->func->type) { + case PSI_T_TO_BOOL: + set->func->handler = psi_to_bool; + break; + case PSI_T_TO_INT: + set->func->handler = psi_to_int; + break; + case PSI_T_TO_FLOAT: + set->func->handler = psi_to_double; + break; + case PSI_T_TO_STRING: + set->func->handler = psi_to_string; + break; + case PSI_T_TO_ARRAY: + set->func->handler = psi_to_array; + break; + case PSI_T_TO_OBJECT: + set->func->handler = psi_to_object; + break; + case PSI_T_VOID: + set->func->handler = psi_to_void; + break; + case PSI_T_ELLIPSIS: + if (set->outer.set && set->outer.set->func->type == PSI_T_TO_ARRAY) { + set->func->handler = psi_to_recursive; + set->inner = set->outer.set->inner; + set->count = set->outer.set->count; + break; + } + /* no break */ + default: + return 0; + } + return 1; +} +static inline void decl_var_arg_v(decl_args *args, va_list argp) { + int argc; + decl_arg **argv; + + memset(args, 0, sizeof(*args)); + + while ((argc = va_arg(argp, int))) { + argv = va_arg(argp, decl_arg **); + while (argc--) { + add_decl_arg(args, *argv++); + } + } +} +static inline int validate_set_value_ex(PSI_Data *data, set_value *set, decl_arg *ref, decl_args *ref_list) { + size_t i; + decl_type *ref_type; + decl_var *set_var = set->vars->vars[0]; + + if (!validate_set_value_handler(set)) { + data->error(set->func->token, PSI_WARNING, "Invalid cast '%s' in `set` statement", set->func->name); + return 0; + } + + for (i = 0; i < set->vars->count; ++i) { + decl_var *svar = set->vars->vars[i]; + if (!svar->arg && !locate_decl_var_arg(svar, ref_list, NULL)) { + data->error(svar->token, PSI_WARNING, "Unknown variable '%s' in `set` statement", svar->name); + return 0; + } + } + + if (!ref) { + ref = set_var->arg; + } + ref_type = real_decl_type(ref->type); + + if (set->count) { + int is_to_array = (set->func->type == PSI_T_TO_ARRAY); + int is_pointer_to_struct = (ref_type->type == PSI_T_STRUCT && ref->var->pointer_level); + + if (!is_to_array && !is_pointer_to_struct) { + data->error(set->func->token, E_WARNING, "Inner `set` statement casts only work with " + "to_array() casts on structs or pointers: %s(%s...", set->func->name, set->vars->vars[0]->name); + return 0; + } + } + if (set->num) { + if (!validate_num_exp(data, ref_list, ref, set->num)) { + return 0; + } + } + + if (ref_type->type == PSI_T_STRUCT) { + /* to_array(struct, to_...) */ + if (!set->outer.set || set->outer.set->inner != set->inner) { + for (i = 0; i < set->count; ++i) { + decl_var *sub_var = set->inner[i]->vars->vars[0]; + decl_arg *sub_ref = locate_struct_member(ref_type->strct, sub_var); + + if (sub_ref) { + if (!validate_set_value_ex(data, set->inner[i], sub_ref, ref_type->strct->args)) { + return 0; + } + } + } + } + } else if (set->count == 1) { + /* to_array(ptr, to_string(*ptr)) */ + decl_var *sub_var = set->inner[0]->vars->vars[0]; + decl_arg *sub_ref = locate_decl_var_arg(sub_var, ref_list, ref); + + if (sub_ref) { + if (strcmp(sub_var->name, set_var->name)) { + data->error(sub_var->token, E_WARNING, "Inner `set` statement casts on pointers must reference the same variable"); + return 0; + } + if (!validate_set_value_ex(data, set->inner[0], sub_ref, ref_list)) { + return 0; + } + } + } else if (set->count > 1) { + data->error(set->func->token, E_WARNING, "Inner `set` statement casts on pointers may only occur once"); + return 0; + } + + return 1; +} +static inline int validate_set_value(PSI_Data *data, set_value *set, ...) { + va_list argp; + decl_args args = {0}; + int check; + + va_start(argp, set); + decl_var_arg_v(&args, argp); + va_end(argp); + + check = validate_set_value_ex(data, set, NULL, &args); + if (args.args) { + free(args.args); + } + return check; +} +static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) { + if (decls) { + size_t i; + + for (i = 0; i < decls->count; ++i) { + if (!strcmp(decls->list[i]->func->var->name, ret->set->vars->vars[0]->name)) { + ret->decl = decls->list[i]->func; + return decls->list[i]; + } + } + } + + return NULL; +} +static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) { + return_stmt *ret; + + /* we must have exactly one ret stmt delcaring the native func to call */ + /* and which type cast to apply */ + if (impl->stmts->ret.count != 1) { + if (impl->stmts->ret.count > 1) { + data->error(impl->stmts->ret.list[1]->token, PSI_WARNING, + "Too many `return` statements for implmentation %s;" + " found %zu, exactly one is needed", + impl->func->name, impl->stmts->ret.count); + } else { + data->error(impl->func->token, PSI_WARNING, + "Missing `return` statement for implementation %s", + impl->func->name); + } + return 0; + } + + ret = impl->stmts->ret.list[0]; + + if (!(impl->decl = locate_impl_decl(data->decls, ret))) { + data->error(ret->token, PSI_WARNING, + "Missing declaration '%s' for `return` statment for implementation %s", + ret->set->vars->vars[0]->name, impl->func->name); + return 0; + } + + if (!validate_set_value(data, ret->set, 1, &ret->decl, impl->decl->args ? (int) impl->decl->args->count : 0, impl->decl->args ? impl->decl->args->args : NULL, 0)) { + return 0; + } + + impl->decl->impl = impl; + + return 1; +} + +static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) { + size_t i, j; + /* we can have multiple let stmts */ + + /* check that we have a decl arg for every let stmt */ + for (i = 0; i < impl->stmts->let.count; ++i) { + let_stmt *let = impl->stmts->let.list[i]; + decl_var *let_var; + int check = 0; + + if (let->val && let->val->kind == PSI_LET_TMP) { + let_var = let->val->data.var; + } else { + let_var = let->var; + } + + if (!locate_decl_var_arg(let_var, impl->decl->args, impl->decl->func)) { + data->error(let_var->token, PSI_WARNING, "Unknown variable '%s' in `let` statement" + " of implementation '%s'", let_var->name, impl->func->name); + return 0; + } + + switch (let->val->kind) { + case PSI_LET_NULL: + break; + case PSI_LET_TMP: + /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */ + /* e.g. let foo = *bar; */ + let->var->pointer_level = let->val->data.var->pointer_level; + let->var->arg = init_decl_arg( + init_decl_type( + real_decl_type(let->val->data.var->arg->type)->type, + real_decl_type(let->val->data.var->arg->type)->name), + init_decl_var( + let->var->name, + let->var->pointer_level, + let->var->array_size)); + break; + case PSI_LET_NUMEXP: + if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.num)) { + return 0; + } + break; + case PSI_LET_CALLOC: + if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.alloc->nmemb)) { + return 0; + } + if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.alloc->size)) { + return 0; + } + break; + case PSI_LET_FUNC: + if (impl->func->args) { + for (j = 0; j < impl->func->args->count; ++j) { + impl_arg *iarg = impl->func->args->args[j]; + + if (!strcmp(let->val->data.func->var->name, iarg->var->name)) { + let->val->data.func->arg = iarg; + check = 1; + break; + } + } + } + if (!check) { + data->error(let->var->token, PSI_WARNING, "Unknown value '$%s' of `let` statement" + " for variable '%s' of implementation '%s'", + let->val->data.func->var->name, let->var->name, impl->func->name); + return 0; + } + break; + } + } + + /* check that we have a let stmt for every decl arg */ + if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) { + decl_arg *darg = impl->decl->args->args[i]; + int check = 0; + + for (j = 0; j < impl->stmts->let.count; ++j) { + let_stmt *let = impl->stmts->let.list[j]; + + if (!strcmp(let->var->name, darg->var->name)) { + darg->let = let; + check = 1; + break; + } + } + if (!check) { + data->error(impl->func->token, PSI_WARNING, + "Missing `let` statement for arg '%s %.*s%s'" + " of declaration '%s' for implementation '%s'", + darg->type->name, (int) darg->var->pointer_level, "*****", + darg->var->name, impl->decl->func->var->name, impl->func->name); + return 0; + } + } + + return 1; +} +static inline int validate_impl_set_stmts(PSI_Data *data, impl *impl) { + size_t i, j, k; + /* we can have any count of set stmts; processing out vars */ + /* check that set stmts reference known variables */ + for (i = 0; i < impl->stmts->set.count; ++i) { + set_stmt *set = impl->stmts->set.list[i]; + int check = 0; + + if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) { + impl_arg *iarg = impl->func->args->args[j]; + + if (!strcmp(set->var->name, iarg->var->name)) { + set->arg = iarg; + check = 1; + break; + } + } + if (!check) { + data->error(set->var->token, PSI_WARNING, "Unknown variable '$%s' of `set` statement" + " of implementation '%s'", + set->var->name, impl->func->name); + return 0; + } + + for (j = 0; j < set->val->vars->count; ++j) { + decl_var *set_var = set->val->vars->vars[j]; + + check = 0; + if (impl->decl->args) { + for (k = 0; k < impl->decl->args->count; ++k) { + decl_arg *set_arg = impl->decl->args->args[k]; + + if (!strcmp(set_var->name, set_arg->var->name)) { + check = 1; + set_var->arg = set_arg; + if (!validate_set_value(data, set->val, 1, &set_arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) { + return 0; + } + break; + } + } + } + if (!check) { + for (k = 0; k < impl->stmts->let.count; ++k) { + let_stmt *let = impl->stmts->let.list[k]; + + /* check temp vars */ + if (let->val && let->val->kind == PSI_LET_TMP) { + if (!strcmp(set_var->name, let->var->name)) { + check = 1; + set_var->arg = let->var->arg; + if (!validate_set_value(data, set->val, 1, &set_var->arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) { + return 0; + } + break; + } + } + } + } + + if (!check) { + data->error(set_var->token, PSI_WARNING, "Unknown value '%s' of `set` statement" + " for variable '$%s' of implementation '%s'", + set_var->name, set->arg->var->name, impl->func->name); + return 0; + } + } + } + return 1; +} +static inline decl *locate_free_decl(decls *decls, free_call *f) { + if (decls) { + size_t i; + + for (i = 0; i < decls->count; ++i) { + if (!strcmp(decls->list[i]->func->var->name, f->func)) { + f->decl = decls->list[i]; + return decls->list[i]; + } + } + } + + return NULL; +} +static inline int validate_impl_free_stmts(PSI_Data *data, impl *impl) { + size_t i, j, k, l; + /* we can have any count of free stmts; freeing any out vars */ + for (i = 0; i < impl->stmts->fre.count; ++i) { + free_stmt *fre = impl->stmts->fre.list[i]; + + for (j = 0; j < fre->calls->count; ++j) { + free_call *free_call = fre->calls->list[j]; + + /* first find the decl of the free func */ + if (!locate_free_decl(data->decls, free_call)) { + data->error(free_call->token, PSI_WARNING, + "Missing declaration '%s' in `free` statement" + " of implementation '%s'", + free_call->func, impl->func->name); + return 0; + } + + + + /* now check for known vars */ + for (l = 0; l < free_call->vars->count; ++l) { + int check = 0; + decl_var *free_var = free_call->vars->vars[l]; + + if (!strcmp(free_var->name, impl->decl->func->var->name)) { + check = 1; + free_var->arg = impl->decl->func; + } else if (impl->decl->args) { + for (k = 0; k < impl->decl->args->count; ++k) { + decl_arg *free_arg = impl->decl->args->args[k]; + + if (!strcmp(free_var->name, free_arg->var->name)) { + check = 1; + free_var->arg = free_arg; + break; + } + } + } + + if (!check) { + data->error(free_var->token, PSI_WARNING, + "Unknown variable '%s' of `free` statement" + " of implementation '%s'", + free_var->name, impl->func->name); + return 0; + } + } + } + } + return 1; +} +static inline int validate_impl_stmts(PSI_Data *data, impl *impl) { + if (!impl->stmts) { + data->error(impl->func->token, PSI_WARNING, + "Missing body for implementation %s!", + impl->func->name); + return 0; + } + + if (!validate_impl_ret_stmt(data, impl)) { + return 0; + } + + if (!validate_impl_let_stmts(data, impl)) { + return 0; + } + if (!validate_impl_set_stmts(data, impl)) { + return 0; + } + if (!validate_impl_free_stmts(data, impl)) { + return 0; + } + + return 1; +} + +static inline int validate_impl_args(PSI_Data *data, impl *impl) { + int def = 0; + size_t i; + + for (i = 0; i < impl->func->args->count; ++i) { + impl_arg *iarg = impl->func->args->args[i]; + + if (iarg->def) { + def = 1; + } else if (def) { + data->error(impl->func->token, PSI_WARNING, + "Non-optional argument %zu '$%s' of implementation '%s'" + " follows optional argument", + i+1, iarg->var->name, impl->func->name); + return 0; + } + } + + return 1; +} +static inline int validate_impl(PSI_Data *data, impl *impl) { + if (!validate_impl_args(data, impl)) { + return 0; + } + return validate_impl_stmts(data, impl); +} + + +int PSI_ContextValidate(PSI_Context *C, PSI_Parser *P) +{ + PSI_Data *D; + void *dlopened = NULL; + size_t count = C->count++; + + C->data = realloc(C->data, C->count * sizeof(*C->data)); + D = PSI_DataExchange(&C->data[count], PSI_DATA(P)); + + if (D->defs) { + size_t i; + + for (i = 0; i < D->defs->count; ++i) { + if (validate_decl_typedef(PSI_DATA(C), D->defs->list[i])) { + C->defs = add_decl_typedef(C->defs, D->defs->list[i]); + } + } + } + if (D->structs) { + size_t i; + + for (i = 0; i < D->structs->count; ++i) { + if (validate_decl_struct(PSI_DATA(C), D->structs->list[i])) { + C->structs = add_decl_struct(C->structs, D->structs->list[i]); + } + } + } + if (D->consts) { + size_t i; + + for (i = 0; i < D->consts->count; ++i) { + if (validate_constant(PSI_DATA(C), D->consts->list[i])) { + C->consts = add_constant(C->consts, D->consts->list[i]); + } + } + } + + if (!validate_lib(D, &dlopened)) { + return 0; + } + + add_decl_lib(&C->psi.libs, dlopened); + + if (D->decls) { + size_t i; + + for (i = 0; i < D->decls->count; ++i) { + if (validate_decl(PSI_DATA(C), dlopened, D->decls->list[i])) { + C->decls = add_decl(C->decls, D->decls->list[i]); + } + } + } + if (D->impls) { + size_t i; + + for (i = 0; i < D->impls->count; ++i) { + if (validate_impl(PSI_DATA(C), D->impls->list[i])) { + C->impls = add_impl(C->impls, D->impls->list[i]); + } + } + } + + return 1; +} + +void PSI_ContextValidatePredef(PSI_Context *C, PSI_Data *D) +{ + size_t i; + + for (i = 0; i < D->defs->count; ++i) { + decl_typedef *def = D->defs->list[i]; + + if (validate_decl_typedef(D, def)) { + C->defs = add_decl_typedef(C->defs, def); + } + } + + for (i = 0; i < D->consts->count; ++i) { + constant *constant = D->consts->list[i]; + + if (validate_constant(D, constant)) { + C->consts = add_constant(C->consts, constant); + } + } + + for (i = 0; i < D->structs->count; ++i) { + decl_struct *dstruct = D->structs->list[i]; + + if (validate_decl_struct(D, dstruct)) { + C->structs = add_decl_struct(C->structs, dstruct); + } + } + + for (i = 0; i < D->decls->count; ++i) { + decl *decl = D->decls->list[i]; + + if (validate_decl(D, NULL, decl)) { + C->decls = add_decl(C->decls, decl); + } + } +} diff --git a/src/engine.c b/src/engine.c new file mode 100644 index 0000000..c3e95c5 --- /dev/null +++ b/src/engine.c @@ -0,0 +1,609 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_psi.h" + +#include "zend_exceptions.h" + +#include "engine.h" +#include "calc.h" +#include "marshal.h" + +size_t psi_t_alignment(token_t t) +{ +#define PSI_ALIGNOF(T) case PSI_T_## T: return ALIGNOF_## T ##_T; + switch (t) { + PSI_ALIGNOF(INT8); + PSI_ALIGNOF(UINT8); + PSI_ALIGNOF(INT16); + PSI_ALIGNOF(UINT16); + PSI_ALIGNOF(INT32); + PSI_ALIGNOF(UINT32); + PSI_ALIGNOF(INT64); + PSI_ALIGNOF(UINT64); + case PSI_T_FLOAT: + return ALIGNOF_FLOAT; + case PSI_T_DOUBLE: + return ALIGNOF_DOUBLE; + case PSI_T_POINTER: + return ALIGNOF_VOID_P; + EMPTY_SWITCH_DEFAULT_CASE(); + } + return 0; +} + +size_t psi_t_size(token_t t) +{ +#define PSI_SIZEOF(T) case PSI_T_## T : return SIZEOF_## T ##_T; + switch (t) { + PSI_SIZEOF(INT8); + PSI_SIZEOF(UINT8); + PSI_SIZEOF(INT16); + PSI_SIZEOF(UINT16); + PSI_SIZEOF(INT32); + PSI_SIZEOF(UINT32); + PSI_SIZEOF(INT64); + PSI_SIZEOF(UINT64); + case PSI_T_FLOAT: + return SIZEOF_FLOAT; + case PSI_T_DOUBLE: + return SIZEOF_DOUBLE; + case PSI_T_POINTER: + return SIZEOF_VOID_P; + EMPTY_SWITCH_DEFAULT_CASE(); + } + return 0; +} + +size_t psi_t_align(token_t t, size_t s) +{ + size_t a = psi_t_alignment(t); + return ((s - 1) | (a - 1)) + 1; +} + +size_t psi_offset_padding(size_t diff, size_t alignment) +{ + if (diff && diff <= ((diff - 1) | (alignment -1)) + 1) { + diff = 0; + } + + return diff; +} + +int psi_internal_type(impl_type *type) +{ + switch (type->type) { + case PSI_T_BOOL: + return _IS_BOOL; + case PSI_T_INT: + return IS_LONG; + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + return IS_DOUBLE; + case PSI_T_STRING: + return IS_STRING; + case PSI_T_ARRAY: + return IS_ARRAY; + default: + return 0; + } +} + +zend_internal_arg_info *psi_internal_arginfo(impl *impl) +{ + size_t i; + zend_internal_arg_info *aip; + zend_internal_function_info *fi; + + aip = calloc(impl->func->args->count + 1 + !!impl->func->args->vararg.name, sizeof(*aip)); + + fi = (zend_internal_function_info *) &aip[0]; + fi->allow_null = 1; + fi->required_num_args = psi_num_min_args(impl); + fi->return_reference = impl->func->return_reference; + fi->type_hint = psi_internal_type(impl->func->return_type); + + if (impl->func->args->vararg.name) { + impl_arg *vararg = impl->func->args->vararg.name; + zend_internal_arg_info *ai = &aip[impl->func->args->count]; + + ai->name = vararg->var->name; + ai->allow_null = 1; + ai->type_hint = psi_internal_type(vararg->type); + if (vararg->var->reference) { + ai->pass_by_reference = 1; + } + ai->is_variadic = 1; + } + + for (i = 0; i < impl->func->args->count; ++i) { + impl_arg *iarg = impl->func->args->args[i]; + zend_internal_arg_info *ai = &aip[i+1]; + + ai->name = iarg->var->name; + ai->type_hint = psi_internal_type(iarg->type); + if (iarg->var->reference) { + ai->pass_by_reference = 1; + } + //if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) { + ai->allow_null = 1; + //} + } + + return aip; +} + +size_t psi_num_min_args(impl *impl) +{ + size_t i, n = impl->func->args->count; + + for (i = 0; i < impl->func->args->count; ++i) { + if (impl->func->args->args[i]->def) { + --n; + } + } + return n; +} + + +static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl) +{ + size_t i; + impl_arg *iarg; + zend_error_handling zeh; + + zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh); + + if (!impl->func->args->count) { + ZEND_RESULT_CODE rv; + + rv = zend_parse_parameters_none(); + zend_restore_error_handling(&zeh); + return rv; + } + + ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->vararg.name ? -1 : impl->func->args->count) + nextarg: + if (impl->func->args->vararg.name && _i >= impl->func->args->count) { + impl_arg *varg = impl->func->args->vararg.name; + iarg = init_impl_arg( + init_impl_type(varg->type->type, varg->type->name), + init_impl_var(varg->var->name, varg->var->reference), + NULL); + + Z_PARAM_OPTIONAL; + if (_i == impl->func->args->count) { + impl->func->args->vararg.args = init_impl_args(iarg); + } else { + add_impl_arg(impl->func->args->vararg.args, iarg); + } + } else { + iarg = impl->func->args->args[_i]; + if (iarg->def) { + Z_PARAM_OPTIONAL; + } + } + if (PSI_T_BOOL == iarg->type->type) { + Z_PARAM_BOOL(iarg->val.zend.bval); + } else if (PSI_T_INT == iarg->type->type) { + Z_PARAM_LONG(iarg->val.zend.lval); + } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) { + Z_PARAM_DOUBLE(iarg->val.dval); + } else if (PSI_T_STRING == iarg->type->type) { + Z_PARAM_STR_EX(iarg->val.zend.str, 1, iarg->var->reference); + if (iarg->val.zend.str) { + zend_string_addref(iarg->val.zend.str); + } + } else if (PSI_T_ARRAY == iarg->type->type) { + Z_PARAM_PROLOGUE(0); + } else if (PSI_T_OBJECT == iarg->type->type) { + Z_PARAM_PROLOGUE(0); + } else if (PSI_T_MIXED == iarg->type->type) { + Z_PARAM_PROLOGUE(0); + } else { + error_code = ZPP_ERROR_FAILURE; + break; + } + iarg->_zv = _arg; + ZVAL_DEREF(iarg->_zv); + if (_i < _num_args) { + goto nextarg; + } + ZEND_PARSE_PARAMETERS_END_EX( + zend_restore_error_handling(&zeh); + return FAILURE + ); + + /* set up defaults */ + for (i = 0; i < impl->func->args->count; ++i) { + if (i >= EX_NUM_ARGS() && iarg->def) { + iarg = impl->func->args->args[i]; + + switch (iarg->type->type) { + case PSI_T_BOOL: + iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0; + break; + case PSI_T_INT: + iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text)); + break; + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + iarg->val.dval = zend_strtod(iarg->def->text, NULL); + break; + case PSI_T_STRING: + /* FIXME */ + iarg->val.zend.str = zend_string_init(&iarg->def->text[1], strlen(iarg->def->text) - 2, 0); + break; + } + } + } + + zend_restore_error_handling(&zeh); + return SUCCESS; +} + +static inline void *psi_do_calloc(let_calloc *alloc) +{ + zend_long n = psi_long_num_exp(alloc->nmemb, NULL), s = psi_long_num_exp(alloc->size, NULL); + void *mem = safe_emalloc(n, s, sizeof(void *)); + memset(mem, 0, n * s + sizeof(void *)); +#if 0 + fprintf(stderr, "calloc: %p\n", mem); +#endif + return mem; +} + +static inline impl_val *psi_let_val(token_t let_func, impl_arg *iarg, impl_val *arg_val, decl_struct *strct, void **to_free) +{ + switch (let_func) { + case PSI_T_BOOLVAL: + if (iarg->type->type == PSI_T_BOOL) { + arg_val->cval = iarg->val.zend.bval; + } else { + arg_val->cval = zend_is_true(iarg->_zv); + } + break; + case PSI_T_INTVAL: + if (iarg->type->type == PSI_T_INT) { + arg_val->lval = iarg->val.zend.lval; + } else { + arg_val->lval = zval_get_long(iarg->_zv); + } + break; + case PSI_T_FLOATVAL: + if (iarg->type->type == PSI_T_FLOAT || iarg->type->type == PSI_T_DOUBLE) { + arg_val->dval = iarg->val.dval; + } else { + arg_val->dval = zval_get_double(iarg->_zv); + } + break; + case PSI_T_PATHVAL: + case PSI_T_STRVAL: + if (iarg->type->type == PSI_T_STRING) { + if (iarg->val.zend.str) { + arg_val->ptr = estrndup(iarg->val.zend.str->val, iarg->val.zend.str->len); + *to_free = arg_val->ptr; + } else { + arg_val->ptr = ""; + } + } else { + zend_string *zs = zval_get_string(iarg->_zv); + arg_val->ptr = estrdup(zs->val); + *to_free = arg_val->ptr; + zend_string_release(zs); + } + if (PSI_T_PATHVAL == let_func) { + if (SUCCESS != php_check_open_basedir(arg_val->ptr)) { + efree(arg_val->ptr); + return NULL; + } + } + break; + case PSI_T_STRLEN: + if (iarg->type->type == PSI_T_STRING) { + if (iarg->val.zend.str) { + arg_val->lval = iarg->val.zend.str->len; + } else { + arg_val->lval = 0; + } + } else { + zend_string *zs = zval_get_string(iarg->_zv); + arg_val->lval = zs->len; + zend_string_release(zs); + } + break; + case PSI_T_ARRVAL: + if (iarg->type->type == PSI_T_ARRAY) { + arg_val = psi_array_to_struct(strct, HASH_OF(iarg->_zv)); + *to_free = arg_val; + } + break; + case PSI_T_OBJVAL: + if (iarg->type->type == PSI_T_OBJECT) { + psi_object *obj; + + if (!instanceof_function(Z_OBJCE_P(iarg->_zv), psi_object_get_class_entry())) { + return NULL; + } + + obj = PSI_OBJ(iarg->_zv, NULL); + arg_val->ptr = obj->data; + } + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + return arg_val; +} + +static inline void *psi_do_let(let_stmt *let) +{ + decl_arg *darg = let->var->arg; + impl_val *arg_val = darg->ptr; + impl_arg *iarg; + + switch (let->val ? let->val->kind : PSI_LET_NULL) { + case PSI_LET_TMP: + memcpy(arg_val, deref_impl_val(let->val->data.var->arg->let->ptr, let->val->data.var), sizeof(*arg_val)); +#if 0 + fprintf(stderr, "LET TMP: %p -> %p\n", + let->val->data.var->arg->let->ptr, + arg_val->ptr); +#endif + break; + case PSI_LET_NULL: + if (darg->var->array_size) { + arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val)); + darg->mem = arg_val->ptr; + } else { + memset(arg_val, 0, sizeof(*arg_val)); + } + break; + case PSI_LET_CALLOC: + arg_val->ptr = psi_do_calloc(let->val->data.alloc); + darg->mem = arg_val->ptr; + break; + case PSI_LET_NUMEXP: + arg_val->zend.lval = psi_long_num_exp(let->val->data.num, NULL); + break; + case PSI_LET_FUNC: + iarg = let->val->data.func->arg; + + if (!(darg->ptr = psi_let_val(let->val->data.func->type, iarg, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem))) { + return NULL; + } + } + + if (let->val && let->val->flags.one.is_reference) { + return let->ptr = &darg->ptr; + } else { + return let->ptr = darg->ptr; + } +} + +static inline void psi_do_set(zval *return_value, set_value *set) +{ + decl_arg *set_arg = set->vars->vars[0]->arg; + + zval_dtor(return_value); + set->func->handler(return_value, set, set_arg->let ? set_arg->let->ptr : set_arg->ptr); +} + +static inline void psi_do_return(zval *return_value, return_stmt *ret) +{ + ret->set->func->handler(return_value, ret->set, ret->set->vars->vars[0]->arg->ptr); +} + +static inline void psi_do_free(free_stmt *fre) +{ + size_t i, j; + + for (i = 0; i < fre->calls->count; ++i) { + free_call *f = fre->calls->list[i]; + + for (j = 0; j < f->vars->count; ++j) { + decl_var *dvar = f->vars->vars[j]; + decl_arg *darg = dvar->arg; + impl_val *fval = darg->let ? darg->let->ptr : darg->ptr; + + f->decl->call.args[j] = deref_impl_val(fval, dvar); + } + + /* FIXME: check in validate_* that free functions return scalar */ + PSI_ContextCall(&PSI_G(context), &f->decl->call, NULL); + } +} + +static inline void psi_clean_array_struct(decl_arg *darg) { + if (darg->let + && darg->let->val->kind == PSI_LET_FUNC + && darg->let->val->data.func->type == PSI_T_ARRVAL) { + decl_type *type = real_decl_type(darg->type); + + if (type->type == PSI_T_STRUCT) { + void **ptr = (void **) ((char *) darg->mem + type->strct->size); + + while (*ptr) { + efree(*ptr++); + } + } + } +} + +static inline void psi_do_clean(impl *impl) +{ + size_t i; + + if (impl->decl->func->ptr != &impl->decl->func->val) { + efree(impl->decl->func->ptr); + impl->decl->func->ptr = &impl->decl->func->val; + } + for (i = 0; i < impl->func->args->count; ++i ) { + impl_arg *iarg = impl->func->args->args[i]; + + switch (iarg->type->type) { + case PSI_T_STRING: + if (iarg->val.zend.str) { + zend_string_release(iarg->val.zend.str); + } + break; + } + } + + if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) { + decl_arg *darg = impl->decl->args->args[i]; + + if (darg->mem) { + psi_clean_array_struct(darg); + efree(darg->mem); + darg->mem = NULL; + } + darg->ptr = &darg->val; + } + + if (impl->func->args->vararg.args) { + free_impl_args(impl->func->args->vararg.args); + impl->func->args->vararg.args = NULL; + } + if (impl->func->args->vararg.types) { + efree(impl->func->args->vararg.types); + impl->func->args->vararg.types = NULL; + } + if (impl->func->args->vararg.values) { + efree(impl->func->args->vararg.values); + impl->func->args->vararg.values = NULL; + } + if (impl->func->args->vararg.free_list) { + void **list = impl->func->args->vararg.free_list; + + while (*list) { + efree(*list++); + } + + efree(impl->func->args->vararg.free_list); + impl->func->args->vararg.free_list = NULL; + } +} + + +static inline void psi_do_args(impl *impl) { + size_t i; + + for (i = 0; i < impl->decl->args->count; ++i) { + impl->decl->call.args[i] = impl->decl->args->args[i]->let->ptr; + } + + if (!impl->decl->func->var->pointer_level) { + decl_type *real = real_decl_type(impl->decl->func->type); + + switch (real->type) { + case PSI_T_STRUCT: + impl->decl->func->ptr = psi_array_to_struct(real->strct, NULL); + break; + } + } +} + +static inline impl_vararg *psi_do_varargs(impl *impl) { + size_t i, j; + impl_vararg *va = &impl->func->args->vararg; + size_t vacount = va->args->count; + + + if (!vacount) { + return NULL; + } + + va->types = ecalloc(vacount, sizeof(*va->types)); + va->values = ecalloc(vacount, sizeof(*va->values)); + + for (i = 0, j = 0; i < vacount; ++i) { + impl_arg *vaarg = va->args->args[i]; + void *to_free = NULL; + token_t let_fn, vatype = va->name->type->type; + + if (vatype == PSI_T_MIXED) { + switch (Z_TYPE_P(vaarg->_zv)) { + case IS_TRUE: + case IS_FALSE: vatype = PSI_T_BOOL; break; + case IS_LONG: vatype = PSI_T_INT; break; + case IS_DOUBLE: vatype = PSI_T_FLOAT; break; + default: vatype = PSI_T_STRING; break; + } + } + + + switch (vatype) { + case PSI_T_BOOL: let_fn = PSI_T_BOOLVAL; break; + case PSI_T_INT: let_fn = PSI_T_INTVAL; break; + case PSI_T_FLOAT: + case PSI_T_DOUBLE: let_fn = PSI_T_FLOATVAL;break; + case PSI_T_STRING: let_fn = PSI_T_STRVAL; break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + + va->types[i] = vatype; + /* FIXME: varargs with struct-by-value :) */ + if (!psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free)) { + return NULL; + } + + if (to_free) { + if (!va->free_list) { + va->free_list = ecalloc(vacount - i + 1, sizeof(*va->free_list)); + } + va->free_list[j++] = to_free; + } + } + + return va; +} + +void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl) +{ + size_t i; + impl_vararg *va = NULL; + + memset(impl->decl->func->ptr, 0, sizeof(impl_val)); + + if (SUCCESS != psi_parse_args(execute_data, impl)) { + return; + } + + for (i = 0; i < impl->stmts->let.count; ++i) { + let_stmt *let = impl->stmts->let.list[i]; + + if (!psi_do_let(let)) { + psi_do_return(return_value, impl->stmts->ret.list[0]); + psi_do_clean(impl); + return; + } + } + + if (impl->decl->args) { + psi_do_args(impl); + + if (impl->func->args->vararg.args) { + va = psi_do_varargs(impl); + } + } + + PSI_ContextCall(&PSI_G(context), &impl->decl->call, va); + psi_do_return(return_value, impl->stmts->ret.list[0]); + + for (i = 0; i < impl->stmts->set.count; ++i) { + set_stmt *set = impl->stmts->set.list[i]; + + if (set->arg->_zv) { + psi_do_set(set->arg->_zv, set->val); + } + } + + for (i = 0; i < impl->stmts->fre.count; ++i) { + free_stmt *fre = impl->stmts->fre.list[i]; + + psi_do_free(fre); + } + psi_do_clean(impl); +} diff --git a/src/engine.h b/src/engine.h new file mode 100644 index 0000000..9a2ddcf --- /dev/null +++ b/src/engine.h @@ -0,0 +1,15 @@ +#ifndef _PSI_ENGINE_H +#define _PSI_ENGINE_H + +size_t psi_t_alignment(token_t t); +size_t psi_t_size(token_t t); +size_t psi_t_align(token_t t, size_t s); + +size_t psi_offset_padding(size_t diff, size_t alignment); +int psi_internal_type(impl_type *type); +zend_internal_arg_info *psi_internal_arginfo(impl *impl); +size_t psi_num_min_args(impl *impl); + +void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl); + +#endif diff --git a/src/libffi.c b/src/libffi.c index 288acd3..1f5bf01 100644 --- a/src/libffi.c +++ b/src/libffi.c @@ -8,6 +8,7 @@ #include "php_psi.h" #include "libffi.h" +#include "engine.h" #undef PACKAGE #undef PACKAGE_BUGREPORT diff --git a/src/libjit.c b/src/libjit.c index 8b9278c..5dd1f71 100644 --- a/src/libjit.c +++ b/src/libjit.c @@ -8,6 +8,7 @@ #include "php_psi.h" #include "libjit.h" +#include "engine.h" #include diff --git a/src/marshal.c b/src/marshal.c new file mode 100644 index 0000000..c75a358 --- /dev/null +++ b/src/marshal.c @@ -0,0 +1,341 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_psi.h" + +#include "marshal.h" +#include "calc.h" + +void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val) +{ + RETVAL_NULL(); +} + +void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val) +{ + psi_to_int(return_value, set, ret_val); + convert_to_boolean(return_value); +} + +void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val) +{ + decl_var *var = set->vars->vars[0]; + token_t t = real_decl_type(var->arg->type)->type; + impl_val *v = deref_impl_val(ret_val, var); + + switch (t) { + case PSI_T_FLOAT: + RETVAL_DOUBLE((double) v->fval); + convert_to_long(return_value); + break; + case PSI_T_DOUBLE: + RETVAL_DOUBLE(v->dval); + convert_to_long(return_value); + break; + case PSI_T_INT8: + RETVAL_LONG(v->i8); + break; + case PSI_T_UINT8: + RETVAL_LONG(v->u8); + break; + case PSI_T_INT16: + RETVAL_LONG(v->i16); + break; + case PSI_T_UINT16: + RETVAL_LONG(v->u16); + break; + case PSI_T_INT32: + RETVAL_LONG(v->i32); + break; + case PSI_T_UINT32: +#if UINT32_MAX >= ZEND_LONG_MAX + if (v->u32 > ZEND_LONG_MAX) { + char d[12] = {0}; + + RETVAL_STRING(zend_print_ulong_to_buf(&d[10], v->u32)); + } else { +#endif + RETVAL_LONG(v->u32); +#if UINT32_MAX >= ZEND_LONG_MAX + } +#endif + break; + case PSI_T_INT64: + RETVAL_LONG(v->i64); + break; + case PSI_T_UINT64: + if (v->u64 > ZEND_LONG_MAX) { + char d[24] = {0}; + + RETVAL_STRING(zend_print_ulong_to_buf(&d[22], v->u64)); + } else { + RETVAL_LONG(v->u64); + } + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } +} + +void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val) +{ + decl_var *var = set->vars->vars[0]; + token_t t = real_decl_type(var->arg->type)->type; + impl_val *v = deref_impl_val(ret_val, var); + + switch (t) { + case PSI_T_FLOAT: + RETVAL_DOUBLE((double) v->fval); + break; + case PSI_T_DOUBLE: + RETVAL_DOUBLE(v->dval); + break; +#ifdef HAVE_LONG_DOUBLE + case PSI_T_LONG_DOUBLE: + RETVAL_DOUBLE((double) v->ldval); + break; +#endif + case PSI_T_INT8: + RETVAL_DOUBLE((double) v->i8); + break; + case PSI_T_UINT8: + RETVAL_DOUBLE((double) v->u8); + break; + case PSI_T_INT16: + RETVAL_DOUBLE((double) v->i16); + break; + case PSI_T_UINT16: + RETVAL_DOUBLE((double) v->u16); + break; + case PSI_T_INT32: + RETVAL_DOUBLE((double) v->i32); + break; + case PSI_T_UINT32: + RETVAL_DOUBLE((double) v->u32); + break; + case PSI_T_INT64: + RETVAL_DOUBLE((double) v->i64); + break; + case PSI_T_UINT64: + RETVAL_DOUBLE((double) v->u64); + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } +} + +void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val) +{ + char *str; + decl_var *var = set->vars->vars[0]; + token_t t = real_decl_type(var->arg->type)->type; + + switch (t) { + case PSI_T_FLOAT: + RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval); + break; + case PSI_T_DOUBLE: + RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval); + break; +#ifdef HAVE_LONG_DOUBLE + case PSI_T_LONG_DOUBLE: + RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->ldval); + break; +#endif + default: + if (!var->arg->var->pointer_level) { + RETVAL_STRINGL(&ret_val->cval, 1); + } else { + ret_val = deref_impl_val(ret_val, var); + if (var->arg->var->array_size) { + str = (char *) ret_val; + } else { + str = ret_val->ptr; + } + if (str) { + if (set->num) { + zend_long n = psi_long_num_exp(set->num, set->outer.val); + RETVAL_STRINGL(str, n); + } else { + RETVAL_STRING(str); + } + } else { + RETVAL_EMPTY_STRING(); + } + } + return; + } + convert_to_string(return_value); +} + + +static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp) +{ + memset(tmp, 0, sizeof(*tmp)); + memcpy(tmp, ((void*) val) + size * i, size); + return tmp; +} + +void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp) +{ + decl_type *type = real_decl_type(spec->type); + + switch (type->type) { + case PSI_T_FLOAT: + mem->fval = (float) zval_get_double(zv); + break; + case PSI_T_DOUBLE: + mem->dval = zval_get_double(zv); + break; + case PSI_T_VOID: + case PSI_T_INT8: + case PSI_T_UINT8: + if (spec->var->pointer_level) { + zend_string *zs = zval_get_string(zv); + *tmp = mem->ptr = estrndup(zs->val, zs->len); + zend_string_release(zs); + break; + } + /* no break */ + default: + mem->zend.lval = zval_get_long(zv); + break; + } +} + +void *psi_array_to_struct(decl_struct *s, HashTable *arr) +{ + size_t i, j = 0; + char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *)); + + if (arr) for (i = 0; i < s->args->count; ++i) { + decl_arg *darg = s->args->args[i]; + zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name)); + + if (entry) { + impl_val val; + void *tmp = NULL; + + memset(&tmp, 0, sizeof(tmp)); + psi_from_zval(&val, darg, entry, &tmp); + memcpy(mem + darg->layout->pos, &val, darg->layout->len); + if (tmp) { + ((void **)(mem + s->size))[j++] = tmp; + } + } + } + return mem; +} + +void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val) +{ + set->outer.set->func->handler(return_value, set, r_val); +} + +void psi_to_array(zval *return_value, set_value *set, impl_val *r_val) +{ + size_t i; + decl_var *var = set->vars->vars[0]; + token_t t = real_decl_type(var->arg->type)->type; + impl_val tmp, *ret_val = deref_impl_val(r_val, var); + + if ((intptr_t) ret_val <= (intptr_t) 0) { + RETURN_NULL(); + } + + array_init(return_value); + + if (t == PSI_T_STRUCT) { + // decl_struct *s = real_decl_type(var->arg->type)->strct; + + if (set->count) { + /* explicit member casts */ + for (i = 0; i < set->count; ++i) { + set_value *sub_set = set->inner[i]; + decl_var *sub_var = sub_set->vars->vars[0]; + + sub_set->outer.val = ret_val; + + if (sub_var->arg) { + impl_val *tmp = NULL, *val; + zval ztmp; + + val = struct_member_ref(sub_var->arg, ret_val, &tmp); + sub_set->func->handler(&ztmp, sub_set, val); + add_assoc_zval(return_value, sub_var->name, &ztmp); + + if (tmp) { + free(tmp); + } + } + } + } + return; + } + + if (var->arg->var->array_size) { + /* to_array(foo[NUMBER]) */ + for (i = 0; i < var->arg->var->array_size; ++i) { + size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t); + impl_val *ptr = iterate(ret_val, size, i, &tmp); + zval ele; + + switch (t) { + case PSI_T_FLOAT: + ZVAL_DOUBLE(&ele, (double) ptr->fval); + break; + case PSI_T_DOUBLE: + ZVAL_DOUBLE(&ele, ptr->dval); + break; + default: + ZVAL_LONG(&ele, ptr->lval); + break; + } + + add_next_index_zval(return_value, &ele); + } + return; + } else if (set->num) { + /* to_array(arr_var, num_expr, to_int(*arr_var)) */ + zval ele; + char *ptr; + zend_long i, n = psi_long_num_exp(set->num, set->outer.val); + size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t); + set_value *sub_set = set->inner[0]; + + sub_set->outer.val = set->outer.val; + for (i = 0; i < n; ++i) { + ptr = (char *) ret_val->ptr + i * size; + sub_set->func->handler(&ele, sub_set, (void *) ptr); + add_next_index_zval(return_value, &ele); + } + } else { + /* to_array(arr_var, to_int(*arr_var)) */ + zval ele; + char *ptr = ret_val->ptr; + size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t); + set_value *sub_set = set->inner[0]; + + sub_set->outer.val = set->outer.val; + while (*(void **) ptr) { + sub_set->func->handler(&ele, sub_set, (void *) ptr); + add_next_index_zval(return_value, &ele); + ptr += size; + } + } +} + +void psi_to_object(zval *return_value, set_value *set, impl_val *r_val) +{ + decl_var *var = set->vars->vars[0]; + impl_val *ret_val = deref_impl_val(r_val, var); + psi_object *obj; + + if ((intptr_t) ret_val->ptr > (intptr_t) 0) { + object_init_ex(return_value, psi_object_get_class_entry()); + obj = PSI_OBJ(return_value, NULL); + obj->data = ret_val->ptr; + } else { + RETVAL_NULL(); + } +} diff --git a/src/marshal.h b/src/marshal.h new file mode 100644 index 0000000..6b2d7fa --- /dev/null +++ b/src/marshal.h @@ -0,0 +1,16 @@ +#ifndef _PSI_MARSHAL_H +#define _PSI_MARSHAL_H + +void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val); +void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val); +void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val); +void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val); +void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val); +void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val); +void psi_to_array(zval *return_value, set_value *set, impl_val *ret_val); +void psi_to_object(zval *return_value, set_value *set, impl_val *ret_val); + +void *psi_array_to_struct(decl_struct *s, HashTable *arr); +void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp); + +#endif diff --git a/src/module.c b/src/module.c index 84d3e95..1fe5bf3 100644 --- a/src/module.c +++ b/src/module.c @@ -1,12 +1,11 @@ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "zend_exceptions.h" #include "zend_constants.h" #include "zend_operators.h" @@ -23,8 +22,6 @@ # define PSI_ENGINE "ffi" #endif -#include - ZEND_DECLARE_MODULE_GLOBALS(psi); PHP_INI_BEGIN() @@ -35,6 +32,11 @@ PHP_INI_END(); static zend_object_handlers psi_object_handlers; static zend_class_entry *psi_class_entry; +zend_class_entry *psi_object_get_class_entry() +{ + return psi_class_entry; +} + void psi_error_wrapper(PSI_Token *t, int type, const char *msg, ...) { va_list argv; @@ -56,1218 +58,13 @@ void psi_verror(int type, const char *fn, unsigned ln, const char *msg, va_list zend_error_cb(type, fn, ln, msg, argv); } -size_t psi_t_alignment(token_t t) -{ -#define PSI_ALIGNOF(T) case PSI_T_## T: return ALIGNOF_## T ##_T; - switch (t) { - PSI_ALIGNOF(INT8); - PSI_ALIGNOF(UINT8); - PSI_ALIGNOF(INT16); - PSI_ALIGNOF(UINT16); - PSI_ALIGNOF(INT32); - PSI_ALIGNOF(UINT32); - PSI_ALIGNOF(INT64); - PSI_ALIGNOF(UINT64); - case PSI_T_FLOAT: - return ALIGNOF_FLOAT; - case PSI_T_DOUBLE: - return ALIGNOF_DOUBLE; - case PSI_T_POINTER: - return ALIGNOF_VOID_P; - EMPTY_SWITCH_DEFAULT_CASE(); - } - return 0; -} - -size_t psi_t_size(token_t t) -{ -#define PSI_SIZEOF(T) case PSI_T_## T : return SIZEOF_## T ##_T; - switch (t) { - PSI_SIZEOF(INT8); - PSI_SIZEOF(UINT8); - PSI_SIZEOF(INT16); - PSI_SIZEOF(UINT16); - PSI_SIZEOF(INT32); - PSI_SIZEOF(UINT32); - PSI_SIZEOF(INT64); - PSI_SIZEOF(UINT64); - case PSI_T_FLOAT: - return SIZEOF_FLOAT; - case PSI_T_DOUBLE: - return SIZEOF_DOUBLE; - case PSI_T_POINTER: - return SIZEOF_VOID_P; - EMPTY_SWITCH_DEFAULT_CASE(); - } - return 0; -} - -size_t psi_t_align(token_t t, size_t s) -{ - size_t a = psi_t_alignment(t); - return ((s - 1) | (a - 1)) + 1; -} - -size_t psi_offset_padding(size_t diff, size_t alignment) -{ - if (diff && diff <= ((diff - 1) | (alignment -1)) + 1) { - diff = 0; - } - - return diff; -} - -int psi_internal_type(impl_type *type) -{ - switch (type->type) { - case PSI_T_BOOL: - return _IS_BOOL; - case PSI_T_INT: - return IS_LONG; - case PSI_T_FLOAT: - case PSI_T_DOUBLE: - return IS_DOUBLE; - case PSI_T_STRING: - return IS_STRING; - case PSI_T_ARRAY: - return IS_ARRAY; - default: - return 0; - } -} - -zend_internal_arg_info *psi_internal_arginfo(impl *impl) -{ - size_t i; - zend_internal_arg_info *aip; - zend_internal_function_info *fi; - - aip = calloc(impl->func->args->count + 1 + !!impl->func->args->vararg.name, sizeof(*aip)); - - fi = (zend_internal_function_info *) &aip[0]; - fi->allow_null = 1; - fi->required_num_args = psi_num_min_args(impl); - fi->return_reference = impl->func->return_reference; - fi->type_hint = psi_internal_type(impl->func->return_type); - - if (impl->func->args->vararg.name) { - impl_arg *vararg = impl->func->args->vararg.name; - zend_internal_arg_info *ai = &aip[impl->func->args->count]; - - ai->name = vararg->var->name; - ai->allow_null = 1; - ai->type_hint = psi_internal_type(vararg->type); - if (vararg->var->reference) { - ai->pass_by_reference = 1; - } - ai->is_variadic = 1; - } - - for (i = 0; i < impl->func->args->count; ++i) { - impl_arg *iarg = impl->func->args->args[i]; - zend_internal_arg_info *ai = &aip[i+1]; - - ai->name = iarg->var->name; - ai->type_hint = psi_internal_type(iarg->type); - if (iarg->var->reference) { - ai->pass_by_reference = 1; - } - //if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) { - ai->allow_null = 1; - //} - } - - return aip; -} - -size_t psi_num_min_args(impl *impl) -{ - size_t i, n = impl->func->args->count; - - for (i = 0; i < impl->func->args->count; ++i) { - if (impl->func->args->args[i]->def) { - --n; - } - } - return n; -} - -void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val) -{ - RETVAL_NULL(); -} - -void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val) -{ - psi_to_int(return_value, set, ret_val); - convert_to_boolean(return_value); -} - -void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val) -{ - decl_var *var = set->vars->vars[0]; - token_t t = real_decl_type(var->arg->type)->type; - impl_val *v = deref_impl_val(ret_val, var); - - switch (t) { - case PSI_T_FLOAT: - RETVAL_DOUBLE((double) v->fval); - convert_to_long(return_value); - break; - case PSI_T_DOUBLE: - RETVAL_DOUBLE(v->dval); - convert_to_long(return_value); - break; - case PSI_T_INT8: - RETVAL_LONG(v->i8); - break; - case PSI_T_UINT8: - RETVAL_LONG(v->u8); - break; - case PSI_T_INT16: - RETVAL_LONG(v->i16); - break; - case PSI_T_UINT16: - RETVAL_LONG(v->u16); - break; - case PSI_T_INT32: - RETVAL_LONG(v->i32); - break; - case PSI_T_UINT32: -#if UINT32_MAX >= ZEND_LONG_MAX - if (v->u32 > ZEND_LONG_MAX) { - char d[12] = {0}; - - RETVAL_STRING(zend_print_ulong_to_buf(&d[10], v->u32)); - } else { -#endif - RETVAL_LONG(v->u32); -#if UINT32_MAX >= ZEND_LONG_MAX - } -#endif - break; - case PSI_T_INT64: - RETVAL_LONG(v->i64); - break; - case PSI_T_UINT64: - if (v->u64 > ZEND_LONG_MAX) { - char d[24] = {0}; - - RETVAL_STRING(zend_print_ulong_to_buf(&d[22], v->u64)); - } else { - RETVAL_LONG(v->u64); - } - break; - EMPTY_SWITCH_DEFAULT_CASE(); - } -} - -void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val) -{ - decl_var *var = set->vars->vars[0]; - token_t t = real_decl_type(var->arg->type)->type; - impl_val *v = deref_impl_val(ret_val, var); - - switch (t) { - case PSI_T_FLOAT: - RETVAL_DOUBLE((double) v->fval); - break; - case PSI_T_DOUBLE: - RETVAL_DOUBLE(v->dval); - break; -#ifdef HAVE_LONG_DOUBLE - case PSI_T_LONG_DOUBLE: - RETVAL_DOUBLE((double) v->ldval); - break; -#endif - case PSI_T_INT8: - RETVAL_DOUBLE((double) v->i8); - break; - case PSI_T_UINT8: - RETVAL_DOUBLE((double) v->u8); - break; - case PSI_T_INT16: - RETVAL_DOUBLE((double) v->i16); - break; - case PSI_T_UINT16: - RETVAL_DOUBLE((double) v->u16); - break; - case PSI_T_INT32: - RETVAL_DOUBLE((double) v->i32); - break; - case PSI_T_UINT32: - RETVAL_DOUBLE((double) v->u32); - break; - case PSI_T_INT64: - RETVAL_DOUBLE((double) v->i64); - break; - case PSI_T_UINT64: - RETVAL_DOUBLE((double) v->u64); - break; - EMPTY_SWITCH_DEFAULT_CASE(); - } -} - -void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val) -{ - char *str; - decl_var *var = set->vars->vars[0]; - token_t t = real_decl_type(var->arg->type)->type; - - switch (t) { - case PSI_T_FLOAT: - RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval); - break; - case PSI_T_DOUBLE: - RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval); - break; -#ifdef HAVE_LONG_DOUBLE - case PSI_T_LONG_DOUBLE: - RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->ldval); - break; -#endif - default: - if (!var->arg->var->pointer_level) { - RETVAL_STRINGL(&ret_val->cval, 1); - } else { - ret_val = deref_impl_val(ret_val, var); - if (var->arg->var->array_size) { - str = (char *) ret_val; - } else { - str = ret_val->ptr; - } - if (str) { - if (set->num) { - zend_long n = psi_long_num_exp(set->num, set->outer.val); - RETVAL_STRINGL(str, n); - } else { - RETVAL_STRING(str); - } - } else { - RETVAL_EMPTY_STRING(); - } - } - return; - } - convert_to_string(return_value); -} - - -static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp) -{ - memset(tmp, 0, sizeof(*tmp)); - memcpy(tmp, ((void*) val) + size * i, size); - return tmp; -} - -void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp) -{ - decl_type *type = real_decl_type(spec->type); - - switch (type->type) { - case PSI_T_FLOAT: - mem->fval = (float) zval_get_double(zv); - break; - case PSI_T_DOUBLE: - mem->dval = zval_get_double(zv); - break; - case PSI_T_VOID: - case PSI_T_INT8: - case PSI_T_UINT8: - if (spec->var->pointer_level) { - zend_string *zs = zval_get_string(zv); - *tmp = mem->ptr = estrndup(zs->val, zs->len); - zend_string_release(zs); - break; - } - /* no break */ - default: - mem->zend.lval = zval_get_long(zv); - break; - } -} - -void *psi_array_to_struct(decl_struct *s, HashTable *arr) -{ - size_t i, j = 0; - char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *)); - - if (arr) for (i = 0; i < s->args->count; ++i) { - decl_arg *darg = s->args->args[i]; - zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name)); - - if (entry) { - impl_val val; - void *tmp = NULL; - - memset(&tmp, 0, sizeof(tmp)); - psi_from_zval(&val, darg, entry, &tmp); - memcpy(mem + darg->layout->pos, &val, darg->layout->len); - if (tmp) { - ((void **)(mem + s->size))[j++] = tmp; - } - } - } - return mem; -} - -void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val) -{ - set->outer.set->func->handler(return_value, set, r_val); -} - -void psi_to_array(zval *return_value, set_value *set, impl_val *r_val) -{ - size_t i; - decl_var *var = set->vars->vars[0]; - token_t t = real_decl_type(var->arg->type)->type; - impl_val tmp, *ret_val = deref_impl_val(r_val, var); - - if ((intptr_t) ret_val <= (intptr_t) 0) { - RETURN_NULL(); - } - - array_init(return_value); - - if (t == PSI_T_STRUCT) { - // decl_struct *s = real_decl_type(var->arg->type)->strct; - - if (set->count) { - /* explicit member casts */ - for (i = 0; i < set->count; ++i) { - set_value *sub_set = set->inner[i]; - decl_var *sub_var = sub_set->vars->vars[0]; - - sub_set->outer.val = ret_val; - - if (sub_var->arg) { - impl_val *tmp = NULL, *val; - zval ztmp; - - val = struct_member_ref(sub_var->arg, ret_val, &tmp); - sub_set->func->handler(&ztmp, sub_set, val); - add_assoc_zval(return_value, sub_var->name, &ztmp); - - if (tmp) { - free(tmp); - } - } - } - } - return; - } - - if (var->arg->var->array_size) { - /* to_array(foo[NUMBER]) */ - for (i = 0; i < var->arg->var->array_size; ++i) { - size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t); - impl_val *ptr = iterate(ret_val, size, i, &tmp); - zval ele; - - switch (t) { - case PSI_T_FLOAT: - ZVAL_DOUBLE(&ele, (double) ptr->fval); - break; - case PSI_T_DOUBLE: - ZVAL_DOUBLE(&ele, ptr->dval); - break; - default: - ZVAL_LONG(&ele, ptr->lval); - break; - } - - add_next_index_zval(return_value, &ele); - } - return; - } else if (set->num) { - /* to_array(arr_var, num_expr, to_int(*arr_var)) */ - zval ele; - char *ptr; - zend_long i, n = psi_long_num_exp(set->num, set->outer.val); - size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t); - set_value *sub_set = set->inner[0]; - - sub_set->outer.val = set->outer.val; - for (i = 0; i < n; ++i) { - ptr = (char *) ret_val->ptr + i * size; - sub_set->func->handler(&ele, sub_set, (void *) ptr); - add_next_index_zval(return_value, &ele); - } - } else { - /* to_array(arr_var, to_int(*arr_var)) */ - zval ele; - char *ptr = ret_val->ptr; - size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t); - set_value *sub_set = set->inner[0]; - - sub_set->outer.val = set->outer.val; - while (*(void **) ptr) { - sub_set->func->handler(&ele, sub_set, (void *) ptr); - add_next_index_zval(return_value, &ele); - ptr += size; - } - } -} - -void psi_to_object(zval *return_value, set_value *set, impl_val *r_val) -{ - decl_var *var = set->vars->vars[0]; - impl_val *ret_val = deref_impl_val(r_val, var); - psi_object *obj; - - if ((intptr_t) ret_val->ptr > (intptr_t) 0) { - object_init_ex(return_value, psi_class_entry); - obj = PSI_OBJ(return_value, NULL); - obj->data = ret_val->ptr; - } else { - RETVAL_NULL(); - } -} - -static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl) -{ - size_t i; - impl_arg *iarg; - zend_error_handling zeh; - - zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh); - - if (!impl->func->args->count) { - ZEND_RESULT_CODE rv; - - rv = zend_parse_parameters_none(); - zend_restore_error_handling(&zeh); - return rv; - } - - ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->vararg.name ? -1 : impl->func->args->count) - nextarg: - if (impl->func->args->vararg.name && _i >= impl->func->args->count) { - impl_arg *varg = impl->func->args->vararg.name; - iarg = init_impl_arg( - init_impl_type(varg->type->type, varg->type->name), - init_impl_var(varg->var->name, varg->var->reference), - NULL); - - Z_PARAM_OPTIONAL; - if (_i == impl->func->args->count) { - impl->func->args->vararg.args = init_impl_args(iarg); - } else { - add_impl_arg(impl->func->args->vararg.args, iarg); - } - } else { - iarg = impl->func->args->args[_i]; - if (iarg->def) { - Z_PARAM_OPTIONAL; - } - } - if (PSI_T_BOOL == iarg->type->type) { - Z_PARAM_BOOL(iarg->val.zend.bval); - } else if (PSI_T_INT == iarg->type->type) { - Z_PARAM_LONG(iarg->val.zend.lval); - } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) { - Z_PARAM_DOUBLE(iarg->val.dval); - } else if (PSI_T_STRING == iarg->type->type) { - Z_PARAM_STR_EX(iarg->val.zend.str, 1, iarg->var->reference); - if (iarg->val.zend.str) { - zend_string_addref(iarg->val.zend.str); - } - } else if (PSI_T_ARRAY == iarg->type->type) { - Z_PARAM_PROLOGUE(0); - } else if (PSI_T_OBJECT == iarg->type->type) { - Z_PARAM_PROLOGUE(0); - } else if (PSI_T_MIXED == iarg->type->type) { - Z_PARAM_PROLOGUE(0); - } else { - error_code = ZPP_ERROR_FAILURE; - break; - } - iarg->_zv = _arg; - ZVAL_DEREF(iarg->_zv); - if (_i < _num_args) { - goto nextarg; - } - ZEND_PARSE_PARAMETERS_END_EX( - zend_restore_error_handling(&zeh); - return FAILURE - ); - - /* set up defaults */ - for (i = 0; i < impl->func->args->count; ++i) { - if (i >= EX_NUM_ARGS() && iarg->def) { - iarg = impl->func->args->args[i]; - - switch (iarg->type->type) { - case PSI_T_BOOL: - iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0; - break; - case PSI_T_INT: - iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text)); - break; - case PSI_T_FLOAT: - case PSI_T_DOUBLE: - iarg->val.dval = zend_strtod(iarg->def->text, NULL); - break; - case PSI_T_STRING: - /* FIXME */ - iarg->val.zend.str = zend_string_init(&iarg->def->text[1], strlen(iarg->def->text) - 2, 0); - break; - } - } - } - - zend_restore_error_handling(&zeh); - return SUCCESS; -} - -static inline void *psi_do_calloc(let_calloc *alloc) -{ - zend_long n = psi_long_num_exp(alloc->nmemb, NULL), s = psi_long_num_exp(alloc->size, NULL); - void *mem = safe_emalloc(n, s, sizeof(void *)); - memset(mem, 0, n * s + sizeof(void *)); -#if 0 - fprintf(stderr, "calloc: %p\n", mem); -#endif - return mem; -} - -static inline impl_val *psi_let_val(token_t let_func, impl_arg *iarg, impl_val *arg_val, decl_struct *strct, void **to_free) -{ - switch (let_func) { - case PSI_T_BOOLVAL: - if (iarg->type->type == PSI_T_BOOL) { - arg_val->cval = iarg->val.zend.bval; - } else { - arg_val->cval = zend_is_true(iarg->_zv); - } - break; - case PSI_T_INTVAL: - if (iarg->type->type == PSI_T_INT) { - arg_val->lval = iarg->val.zend.lval; - } else { - arg_val->lval = zval_get_long(iarg->_zv); - } - break; - case PSI_T_FLOATVAL: - if (iarg->type->type == PSI_T_FLOAT || iarg->type->type == PSI_T_DOUBLE) { - arg_val->dval = iarg->val.dval; - } else { - arg_val->dval = zval_get_double(iarg->_zv); - } - break; - case PSI_T_PATHVAL: - case PSI_T_STRVAL: - if (iarg->type->type == PSI_T_STRING) { - if (iarg->val.zend.str) { - arg_val->ptr = estrndup(iarg->val.zend.str->val, iarg->val.zend.str->len); - *to_free = arg_val->ptr; - } else { - arg_val->ptr = ""; - } - } else { - zend_string *zs = zval_get_string(iarg->_zv); - arg_val->ptr = estrdup(zs->val); - *to_free = arg_val->ptr; - zend_string_release(zs); - } - if (PSI_T_PATHVAL == let_func) { - if (SUCCESS != php_check_open_basedir(arg_val->ptr)) { - efree(arg_val->ptr); - return NULL; - } - } - break; - case PSI_T_STRLEN: - if (iarg->type->type == PSI_T_STRING) { - if (iarg->val.zend.str) { - arg_val->lval = iarg->val.zend.str->len; - } else { - arg_val->lval = 0; - } - } else { - zend_string *zs = zval_get_string(iarg->_zv); - arg_val->lval = zs->len; - zend_string_release(zs); - } - break; - case PSI_T_ARRVAL: - if (iarg->type->type == PSI_T_ARRAY) { - arg_val = psi_array_to_struct(strct, HASH_OF(iarg->_zv)); - *to_free = arg_val; - } - break; - case PSI_T_OBJVAL: - if (iarg->type->type == PSI_T_OBJECT) { - psi_object *obj; - - if (!instanceof_function(Z_OBJCE_P(iarg->_zv), psi_class_entry)) { - return NULL; - } - - obj = PSI_OBJ(iarg->_zv, NULL); - arg_val->ptr = obj->data; - } - break; - EMPTY_SWITCH_DEFAULT_CASE(); - } - return arg_val; -} - -static inline void *psi_do_let(let_stmt *let) -{ - decl_arg *darg = let->var->arg; - impl_val *arg_val = darg->ptr; - impl_arg *iarg; - - switch (let->val ? let->val->kind : PSI_LET_NULL) { - case PSI_LET_TMP: - memcpy(arg_val, deref_impl_val(let->val->data.var->arg->let->ptr, let->val->data.var), sizeof(*arg_val)); -#if 0 - fprintf(stderr, "LET TMP: %p -> %p\n", - let->val->data.var->arg->let->ptr, - arg_val->ptr); -#endif - break; - case PSI_LET_NULL: - if (darg->var->array_size) { - arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val)); - darg->mem = arg_val->ptr; - } else { - memset(arg_val, 0, sizeof(*arg_val)); - } - break; - case PSI_LET_CALLOC: - arg_val->ptr = psi_do_calloc(let->val->data.alloc); - darg->mem = arg_val->ptr; - break; - case PSI_LET_NUMEXP: - arg_val->zend.lval = psi_long_num_exp(let->val->data.num, NULL); - break; - case PSI_LET_FUNC: - iarg = let->val->data.func->arg; - - if (!(darg->ptr = psi_let_val(let->val->data.func->type, iarg, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem))) { - return NULL; - } - } - - if (let->val && let->val->flags.one.is_reference) { - return let->ptr = &darg->ptr; - } else { - return let->ptr = darg->ptr; - } -} - -static inline void psi_do_set(zval *return_value, set_value *set) -{ - decl_arg *set_arg = set->vars->vars[0]->arg; - - zval_dtor(return_value); - set->func->handler(return_value, set, set_arg->let ? set_arg->let->ptr : set_arg->ptr); -} - -static inline void psi_do_return(zval *return_value, return_stmt *ret) -{ - ret->set->func->handler(return_value, ret->set, ret->set->vars->vars[0]->arg->ptr); -} - -static inline void psi_do_free(free_stmt *fre) -{ - size_t i, j; - - for (i = 0; i < fre->calls->count; ++i) { - free_call *f = fre->calls->list[i]; - - for (j = 0; j < f->vars->count; ++j) { - decl_var *dvar = f->vars->vars[j]; - decl_arg *darg = dvar->arg; - impl_val *fval = darg->let ? darg->let->ptr : darg->ptr; - - f->decl->call.args[j] = deref_impl_val(fval, dvar); - } - - /* FIXME: check in validate_* that free functions return scalar */ - PSI_ContextCall(&PSI_G(context), &f->decl->call, NULL); - } -} - -static inline void psi_clean_array_struct(decl_arg *darg) { - if (darg->let - && darg->let->val->kind == PSI_LET_FUNC - && darg->let->val->data.func->type == PSI_T_ARRVAL) { - decl_type *type = real_decl_type(darg->type); - - if (type->type == PSI_T_STRUCT) { - void **ptr = (void **) ((char *) darg->mem + type->strct->size); - - while (*ptr) { - efree(*ptr++); - } - } - } -} - -static inline void psi_do_clean(impl *impl) -{ - size_t i; - - if (impl->decl->func->ptr != &impl->decl->func->val) { - efree(impl->decl->func->ptr); - impl->decl->func->ptr = &impl->decl->func->val; - } - for (i = 0; i < impl->func->args->count; ++i ) { - impl_arg *iarg = impl->func->args->args[i]; - - switch (iarg->type->type) { - case PSI_T_STRING: - if (iarg->val.zend.str) { - zend_string_release(iarg->val.zend.str); - } - break; - } - } - - if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) { - decl_arg *darg = impl->decl->args->args[i]; - - if (darg->mem) { - psi_clean_array_struct(darg); - efree(darg->mem); - darg->mem = NULL; - } - darg->ptr = &darg->val; - } - - if (impl->func->args->vararg.args) { - free_impl_args(impl->func->args->vararg.args); - impl->func->args->vararg.args = NULL; - } - if (impl->func->args->vararg.types) { - efree(impl->func->args->vararg.types); - impl->func->args->vararg.types = NULL; - } - if (impl->func->args->vararg.values) { - efree(impl->func->args->vararg.values); - impl->func->args->vararg.values = NULL; - } - if (impl->func->args->vararg.free_list) { - void **list = impl->func->args->vararg.free_list; - - while (*list) { - efree(*list++); - } - - efree(impl->func->args->vararg.free_list); - impl->func->args->vararg.free_list = NULL; - } -} - -static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *strct, impl_val *res) { - impl_val *ref, *tmp = NULL; - - switch (exp->t) { - case PSI_T_NUMBER: - switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) res, (double *) res, 0)) { - case IS_LONG: - return PSI_T_INT64; - case IS_DOUBLE: - return PSI_T_DOUBLE; - } - break; - - case PSI_T_NSNAME: - switch (exp->u.cnst->type->type) { - case PSI_T_INT: - res->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval; - return PSI_T_INT64; - case PSI_T_FLOAT: - res->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval; - return PSI_T_DOUBLE; - default: - return 0; - } - break; - - case PSI_T_NAME: - if (strct) { - ref = struct_member_ref(exp->u.dvar->arg, strct, &tmp); - } else if (exp->u.dvar->arg->let) { - ref = exp->u.dvar->arg->let->ptr; - } else { - ref = exp->u.dvar->arg->ptr; - } - switch (real_decl_type(exp->u.dvar->arg->type)->type) { - case PSI_T_INT8: - case PSI_T_UINT8: - case PSI_T_INT16: - case PSI_T_UINT16: - case PSI_T_INT32: - case PSI_T_UINT32: - case PSI_T_INT64: - case PSI_T_UINT64: - memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res)); - if (tmp) { - free(tmp); - } - return real_decl_type(exp->u.dvar->arg->type)->type; - - case PSI_T_FLOAT: - case PSI_T_DOUBLE: - memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res)); - if (tmp) { - free(tmp); - } - return real_decl_type(exp->u.dvar->arg->type)->type; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - return 0; -} - -int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) { - impl_val num = {0}; - int num_type = psi_calc_num_exp_value(exp, strct, &num); - - if (exp->operand) { - impl_val tmp = {0}; - int tmp_type = psi_calc_num_exp(exp->operand, strct, &tmp); - - return exp->calculator(num_type, &num, tmp_type, &tmp, res); - } - - memcpy(res, &num, sizeof(*res)); - return num_type; -} - -#define PRIfval "f" -#define PRIdval "lf" -#define PRIldval "Lf" - -#define PSI_CALC_OP(var) do { \ - const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \ - res->var = PSI_CALC(v1->var, v2->var); \ - if (!res->var) fprintf(stderr, fmt, v1->var, v2->var, res->var); \ -} while (0) -#define PSI_CALC_OP2(vres, var1, var2) do { \ - const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \ - res->vres = PSI_CALC(v1->var1, v2->var2); \ - if (!res->vres) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \ -} while(0) - -#ifdef HAVE_LONG_DOUBLE -#define PSI_CALC_NO_LD -#define PSI_CALC_OP_LD PSI_CALC_OP(ldval) -#define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval) -#define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2) -#else -#define PSI_CALC_NO_LD abort() -#define PSI_CALC_OP_LD PSI_CALC_NO_LD -#define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD -#define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD -#endif - -#define PSI_CALC_FN(op) int psi_calc_##op(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res) \ -{ \ - if (t1 == t2) { \ - switch (t1) { \ - case PSI_T_FLOAT: PSI_CALC_OP(fval); break; \ - case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; \ - case PSI_T_LONG_DOUBLE: PSI_CALC_OP_LD; break; \ - case PSI_T_INT8: PSI_CALC_OP(i8); break; \ - case PSI_T_UINT8: PSI_CALC_OP(u8); break; \ - case PSI_T_INT16: PSI_CALC_OP(i16); break; \ - case PSI_T_UINT16: PSI_CALC_OP(u16); break; \ - case PSI_T_INT32: PSI_CALC_OP(i32); break; \ - case PSI_T_UINT32: PSI_CALC_OP(u32); break; \ - case PSI_T_INT64: PSI_CALC_OP(i64); break; \ - case PSI_T_UINT64: PSI_CALC_OP(u64); break; \ - EMPTY_SWITCH_DEFAULT_CASE(); \ - } \ - return t1; \ - } else if (t1 == PSI_T_DOUBLE) { \ - switch (t2) { \ - case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(dval); return t2; \ - case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; \ - case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; \ - case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; \ - case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; \ - case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; \ - case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; \ - case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; \ - case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; \ - case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; \ - EMPTY_SWITCH_DEFAULT_CASE(); \ - } \ - return t1; \ - } else if (t2 == PSI_T_DOUBLE) { \ - switch (t1) { \ - case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(dval); return t1; \ - case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; \ - case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; \ - case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; \ - case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; \ - case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; \ - case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; \ - case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; \ - case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; \ - case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; \ - EMPTY_SWITCH_DEFAULT_CASE(); \ - } \ - return t2; \ - } else if (t1 == PSI_T_LONG_DOUBLE) { \ - PSI_CALC_NO_LD; \ - switch (t2) { \ - case PSI_T_DOUBLE: PSI_CALC_OP2_LD1(dval); break; \ - case PSI_T_FLOAT: PSI_CALC_OP2_LD1(fval); break; \ - case PSI_T_INT8: PSI_CALC_OP2_LD1(i8); break; \ - case PSI_T_UINT8: PSI_CALC_OP2_LD1(u8); break; \ - case PSI_T_INT16: PSI_CALC_OP2_LD1(i16); break; \ - case PSI_T_UINT16: PSI_CALC_OP2_LD1(u16); break; \ - case PSI_T_INT32: PSI_CALC_OP2_LD1(i32); break; \ - case PSI_T_UINT32: PSI_CALC_OP2_LD1(u32); break; \ - case PSI_T_INT64: PSI_CALC_OP2_LD1(i64); break; \ - case PSI_T_UINT64: PSI_CALC_OP2_LD1(u64); break; \ - EMPTY_SWITCH_DEFAULT_CASE(); \ - } \ - return t1; \ - } else if (t2 == PSI_T_LONG_DOUBLE) { \ - PSI_CALC_NO_LD; \ - switch (t1) { \ - case PSI_T_DOUBLE: PSI_CALC_OP2_LD2(dval); break; \ - case PSI_T_FLOAT: PSI_CALC_OP2_LD2(fval); break; \ - case PSI_T_INT8: PSI_CALC_OP2_LD2(i8); break; \ - case PSI_T_UINT8: PSI_CALC_OP2_LD2(u8); break; \ - case PSI_T_INT16: PSI_CALC_OP2_LD2(i16); break; \ - case PSI_T_UINT16: PSI_CALC_OP2_LD2(u16); break; \ - case PSI_T_INT32: PSI_CALC_OP2_LD2(i32); break; \ - case PSI_T_UINT32: PSI_CALC_OP2_LD2(u32); break; \ - case PSI_T_INT64: PSI_CALC_OP2_LD2(i64); break; \ - case PSI_T_UINT64: PSI_CALC_OP2_LD2(u64); break; \ - EMPTY_SWITCH_DEFAULT_CASE(); \ - } \ - return t2; \ - } else if (t1 == PSI_T_FLOAT) { \ - switch (t2) { \ - case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(fval); return t2; \ - case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; \ - case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; \ - case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; \ - case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; \ - case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; \ - case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; \ - case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; \ - case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; \ - case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; \ - EMPTY_SWITCH_DEFAULT_CASE(); \ - } \ - return t1; \ - } else if (t2 == PSI_T_FLOAT) { \ - switch (t1) { \ - case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(fval); return t1; \ - case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; \ - case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; \ - case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; \ - case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; \ - case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; \ - case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; \ - case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; \ - case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; \ - case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; \ - EMPTY_SWITCH_DEFAULT_CASE(); \ - } \ - return t2; \ - } else { \ - int64_t sval1 = v1->i64, sval2 = v2->i64; \ - uint64_t uval1 = v1->u64, uval2 = v2->u64; \ - switch (t1) { \ - case PSI_T_INT8: sval1 >>= 8; \ - case PSI_T_INT16: sval1 >>= 8; \ - case PSI_T_INT32: sval1 >>= 8; \ - case PSI_T_INT64: \ - switch (t2) { \ - case PSI_T_INT8: sval2 >>= 8; \ - case PSI_T_INT16: sval2 >>= 8; \ - case PSI_T_INT32: sval2 >>= 8; \ - case PSI_T_INT64: \ - res->i64 = PSI_CALC(sval1 , sval2); \ - return PSI_T_INT64; \ - case PSI_T_UINT8: uval2 >>= 8; \ - case PSI_T_UINT16: uval2 >>= 8; \ - case PSI_T_UINT32: uval2 >>= 8; \ - case PSI_T_UINT64: \ - res->i64 = PSI_CALC(sval1, uval2); \ - return PSI_T_INT64; \ - } \ - break; \ - case PSI_T_UINT8: uval1 >>= 8; \ - case PSI_T_UINT16: uval1 >>= 8; \ - case PSI_T_UINT32: uval1 >>= 8; \ - case PSI_T_UINT64: \ - switch (t2) { \ - case PSI_T_INT8: sval2 >>= 8; \ - case PSI_T_INT16: sval2 >>= 8; \ - case PSI_T_INT32: sval2 >>= 8; \ - case PSI_T_INT64: \ - res->i64 = PSI_CALC(uval1, sval2); \ - return PSI_T_INT64; \ - case PSI_T_UINT8: uval2 >>= 8; \ - case PSI_T_UINT16: uval2 >>= 8; \ - case PSI_T_UINT32: uval2 >>= 8; \ - case PSI_T_UINT64: \ - res->u64 = PSI_CALC(uval1, uval2); \ - return PSI_T_UINT64; \ - } \ - break; \ - } \ - } \ - ZEND_ASSERT(0); \ - return 0; \ -} - -#undef PSI_CALC -#define PSI_CALC(var1, var2) (var1) + (var2) -PSI_CALC_FN(add) -#undef PSI_CALC -#define PSI_CALC(var1, var2) (var1) * (var2) -PSI_CALC_FN(mul) -#undef PSI_CALC -#define PSI_CALC(var1, var2) (var1) - (var2) -PSI_CALC_FN(sub) -#undef PSI_CALC -#define PSI_CALC(var1, var2) (var1) / (var2) -PSI_CALC_FN(div) - -static inline void psi_do_args(impl *impl) { - size_t i; - - for (i = 0; i < impl->decl->args->count; ++i) { - impl->decl->call.args[i] = impl->decl->args->args[i]->let->ptr; - } - - if (!impl->decl->func->var->pointer_level) { - decl_type *real = real_decl_type(impl->decl->func->type); - - switch (real->type) { - case PSI_T_STRUCT: - impl->decl->func->ptr = psi_array_to_struct(real->strct, NULL); - break; - } - } -} - -static inline impl_vararg *psi_do_varargs(impl *impl) { - size_t i, j; - impl_vararg *va = &impl->func->args->vararg; - size_t vacount = va->args->count; - - - if (!vacount) { - return NULL; - } - - va->types = ecalloc(vacount, sizeof(*va->types)); - va->values = ecalloc(vacount, sizeof(*va->values)); - - for (i = 0, j = 0; i < vacount; ++i) { - impl_arg *vaarg = va->args->args[i]; - void *to_free = NULL; - token_t let_fn, vatype = va->name->type->type; - - if (vatype == PSI_T_MIXED) { - switch (Z_TYPE_P(vaarg->_zv)) { - case IS_TRUE: - case IS_FALSE: vatype = PSI_T_BOOL; break; - case IS_LONG: vatype = PSI_T_INT; break; - case IS_DOUBLE: vatype = PSI_T_FLOAT; break; - default: vatype = PSI_T_STRING; break; - } - } - - - switch (vatype) { - case PSI_T_BOOL: let_fn = PSI_T_BOOLVAL; break; - case PSI_T_INT: let_fn = PSI_T_INTVAL; break; - case PSI_T_FLOAT: - case PSI_T_DOUBLE: let_fn = PSI_T_FLOATVAL;break; - case PSI_T_STRING: let_fn = PSI_T_STRVAL; break; - EMPTY_SWITCH_DEFAULT_CASE(); - } - - va->types[i] = vatype; - /* FIXME: varargs with struct-by-value :) */ - if (!psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free)) { - return NULL; - } - - if (to_free) { - if (!va->free_list) { - va->free_list = ecalloc(vacount - i + 1, sizeof(*va->free_list)); - } - va->free_list[j++] = to_free; - } - } - - return va; -} - -void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl) -{ - size_t i; - impl_vararg *va = NULL; - - memset(impl->decl->func->ptr, 0, sizeof(impl_val)); - - if (SUCCESS != psi_parse_args(execute_data, impl)) { - return; - } - - for (i = 0; i < impl->stmts->let.count; ++i) { - let_stmt *let = impl->stmts->let.list[i]; - - if (!psi_do_let(let)) { - psi_do_return(return_value, impl->stmts->ret.list[0]); - psi_do_clean(impl); - return; - } - } - - if (impl->decl->args) { - psi_do_args(impl); - - if (impl->func->args->vararg.args) { - va = psi_do_varargs(impl); - } - } - - PSI_ContextCall(&PSI_G(context), &impl->decl->call, va); - psi_do_return(return_value, impl->stmts->ret.list[0]); - - for (i = 0; i < impl->stmts->set.count; ++i) { - set_stmt *set = impl->stmts->set.list[i]; - - if (set->arg->_zv) { - psi_do_set(set->arg->_zv, set->val); - } - } - - for (i = 0; i < impl->stmts->fre.count; ++i) { - free_stmt *fre = impl->stmts->fre.list[i]; - - psi_do_free(fre); - } - psi_do_clean(impl); -} - static void psi_object_free(zend_object *o) { psi_object *obj = PSI_OBJ(NULL, o); if (obj->data) { - // free(obj->data); + /* FIXME: how about registering a destructor? + // free(obj->data); */ obj->data = NULL; } zend_object_std_dtor(o);