X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;ds=sidebyside;f=src%2Fengine.c;h=6fba400c3dd46f11bec54f32f5905fb62cd8efc0;hb=5e240548ba570610ce0dbc248a2b7654a0e080fa;hp=a4bf0d7aced6d50e3cce84b58bf85914bd204855;hpb=8ea12c5ca367010b2d5024e68849e06af9300d61;p=m6w6%2Fext-psi diff --git a/src/engine.c b/src/engine.c index a4bf0d7..6fba400 100644 --- a/src/engine.c +++ b/src/engine.c @@ -1,67 +1,27 @@ #ifdef HAVE_CONFIG_H # include "config.h" +#else +# include "php_config.h" #endif #include "php.h" #include "php_psi.h" #include "zend_exceptions.h" +#include "zend_interfaces.h" +#include "ext/spl/spl_iterators.h" #include "parser.h" #include "engine.h" #include "calc.h" #include "marshal.h" -size_t psi_t_alignment(token_t t) +static inline void psi_do_set(zval *return_value, set_value *set) { -#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: - case PSI_T_FUNCTION: - return ALIGNOF_VOID_P; - case PSI_T_ENUM: - return ALIGNOF_INT; - EMPTY_SWITCH_DEFAULT_CASE(); - } - return 0; -} + decl_arg *set_arg = set->vars->vars[0]->arg; -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: - case PSI_T_FUNCTION: - return SIZEOF_VOID_P; - case PSI_T_ENUM: - return SIZEOF_INT; - EMPTY_SWITCH_DEFAULT_CASE(); - } - return 0; + zval_dtor(return_value); + set->func->handler(return_value, set, set_arg->let); } int psi_internal_type(impl_type *type) @@ -83,6 +43,43 @@ int psi_internal_type(impl_type *type) } } +zend_long psi_zval_count(zval *zvalue) +{ + /* mimic PHP count() */ + zend_long count; + zval retval; + + switch (Z_TYPE_P(zvalue)) { + default: + count = 1; + break; + case IS_NULL: + count = 0; + break; + case IS_ARRAY: + count = zend_array_count(Z_ARRVAL_P(zvalue)); + break; + case IS_OBJECT: + count = 1; + if (Z_OBJ_HT_P(zvalue)->count_elements) { + if (SUCCESS == Z_OBJ_HT_P(zvalue)->count_elements(zvalue, &count)) { + break; + } + } + + if (instanceof_function(Z_OBJCE_P(zvalue), spl_ce_Countable)) { + zend_call_method_with_0_params(zvalue, NULL, NULL, "count", &retval); + if (Z_TYPE(retval) != IS_UNDEF) { + count = zval_get_long(&retval); + zval_ptr_dtor(&retval); + } + } + break; + } + + return count; +} + zend_internal_arg_info *psi_internal_arginfo(impl *impl) { size_t i; @@ -258,23 +255,15 @@ static inline void *psi_do_calloc(let_calloc *alloc) 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) -{ - abort(); - return arg_val; -} - -static inline impl_val *psi_let_func(let_func *func, decl_arg *darg) { - return darg->ptr = func->handler(darg->ptr, darg->type, func->var->arg, &darg->mem); -} +static inline impl_val *psi_let_func(let_func *func, decl_arg *darg); -static inline void *psi_do_let(let_stmt *let) +static inline void *psi_let_val(let_val *val, decl_arg *darg) { - decl_arg *darg = let->var->arg; + ZEND_ASSERT(darg); - switch (let->val ? let->val->kind : PSI_LET_NULL) { + switch (val ? val->kind : PSI_LET_NULL) { case PSI_LET_TMP: - memcpy(darg->ptr, deref_impl_val(let->val->data.var->arg->let, let->val->data.var), sizeof(impl_val)); + memcpy(darg->ptr, deref_impl_val(val->data.var->arg->let, val->data.var), sizeof(impl_val)); break; case PSI_LET_NULL: if (darg->var->array_size) { @@ -285,29 +274,167 @@ static inline void *psi_do_let(let_stmt *let) } break; case PSI_LET_CALLOC: - darg->val.ptr = psi_do_calloc(let->val->data.alloc); + darg->val.ptr = psi_do_calloc(val->data.alloc); darg->mem = darg->val.ptr; break; - case PSI_LET_CALLBACK: - darg->val.ptr = let->val->data.callback->decl->call.sym; - break; case PSI_LET_NUMEXP: - darg->val.zend.lval = psi_long_num_exp(let->val->data.num, NULL); + darg->val.zend.lval = psi_long_num_exp(val->data.num, NULL); + break; + case PSI_LET_CALLBACK: + darg->val.ptr = val->data.callback->decl->call.sym; break; case PSI_LET_FUNC: - if (!psi_let_func(let->val->data.func, darg)) { + if (!psi_let_func(val->data.func, darg)) { return NULL; } break; } - if (let->val && let->val->flags.one.is_reference) { + if (val && val->is_reference) { return darg->let = &darg->ptr; } else { return darg->let = darg->ptr; } } +static inline impl_val *psi_let_func_ex(let_func *func, void *dptr, decl_type *dtype, decl_var *dvar, token_t itype, impl_val *ival, zval *zvalue, void **to_free) { + switch (func->type) { + case PSI_T_BOOLVAL: + return psi_let_boolval(dptr, dtype, itype, ival, zvalue, to_free); + case PSI_T_INTVAL: + return psi_let_intval(dptr, dtype, itype, ival, zvalue, to_free); + case PSI_T_FLOATVAL: + return psi_let_floatval(dptr, dtype, itype, ival, zvalue, to_free); + case PSI_T_STRVAL: + return psi_let_strval(dptr, dtype, itype, ival, zvalue, to_free); + case PSI_T_STRLEN: + return psi_let_strlen(dptr, dtype, itype, ival, zvalue, to_free); + case PSI_T_PATHVAL: + return psi_let_pathval(dptr, dtype, itype, ival, zvalue, to_free); + case PSI_T_OBJVAL: + return psi_let_objval(dptr, dtype, itype, ival, zvalue, to_free); + case PSI_T_ZVAL: + return psi_let_zval(dptr, dtype, itype, ival, zvalue, to_free); + case PSI_T_VOID: + return psi_let_void(dptr, dtype, itype, ival, zvalue, to_free); + case PSI_T_COUNT: + return psi_let_count(dptr, dtype, itype, ival, zvalue, to_free); + case PSI_T_ARRVAL: + if (func->inner) { + char *mem = NULL; + size_t i, j = 0; + decl_type *real; + decl_args *args = extract_decl_type_args(dtype, &real); + + if (itype != PSI_T_ARRAY) { + SEPARATE_ARG_IF_REF(zvalue); + convert_to_array(zvalue); + } + + if (args) { + size_t size = extract_decl_type_size(real, NULL); + + mem = ecalloc(1, size + args->count * sizeof(void *)); + + for (i = 0; i < args->count; ++i) { + decl_arg *darg = args->args[i]; + let_val *lval = locate_let_vals_val(func->inner, darg->var->name); + impl_val *ptr = NULL; + + if (lval) { + if ((ptr = psi_let_val(lval, darg))) { + memcpy(mem + darg->layout->pos, ptr, darg->layout->len); + if (darg->mem) { + ((void **)(mem + size))[j++] = darg->mem; + } + } + if (real->type == PSI_T_UNION) { + break; + } + } + } + } else { + zval *zv; + let_val *inner = func->inner->vals[0]; + decl_var *sub_var; + size_t size; + + if (inner->var) { + sub_var = inner->var; + } else { + sub_var = copy_decl_var(dvar); + assert(sub_var->pointer_level); + --sub_var->pointer_level; + } + + size = sub_var->pointer_level ? SIZEOF_VOID_P : extract_decl_type_size(real, NULL); + mem = ecalloc(1, size * (1 + zend_array_count(Z_ARRVAL_P(zvalue)))); + + ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(zvalue), zv) + { + void *tmp = NULL; + impl_val val = {0}, *ptr, *sub; + + ptr = psi_let_func_ex(inner->data.func, &val, real, dvar, 0, NULL, zv, &tmp); + sub = deref_impl_val(ptr, sub_var); + + memcpy(&mem[size * j++], &sub, size); + } + ZEND_HASH_FOREACH_END(); + + if (sub_var != inner->var) { + free_decl_var(sub_var); + } + } + return *to_free = mem; + } else { + return psi_let_arrval(dptr, dtype, dvar, itype, ival, zvalue, to_free); + } + break; + default: + assert(0); + } + return NULL; +} + +static inline impl_val *psi_let_func(let_func *func, decl_arg *darg) { + + if (func->var->arg) { + return darg->ptr = psi_let_func_ex(func, + darg->ptr, darg->type, darg->var, + func->var->arg->type->type, + &func->var->arg->val, + func->var->arg->_zv, + &darg->mem); + } else { + impl_var *ivar = locate_let_val_impl_var(func->outer); + zval *entry = zend_symtable_str_find(Z_ARRVAL_P(ivar->arg->_zv), func->var->name+1, strlen(func->var->name)-1); + impl_arg *iarg = init_impl_arg( + init_impl_type(PSI_T_MIXED, "mixed"), + copy_impl_var(func->var), NULL); + + func->var->arg = iarg; + if (entry) { + iarg->_zv = entry; + } else { + zval ztmp; + + ZVAL_NULL(&ztmp); + iarg->_zv = zend_symtable_str_update_ind(Z_ARRVAL_P(ivar->arg->_zv), func->var->name+1, strlen(func->var->name)-1, &ztmp); + } + + psi_let_func(func, darg); + free_impl_arg(iarg); + return darg->ptr; + } + +} + +static inline void *psi_do_let(let_stmt *let) +{ + return psi_let_val(let->val, let->val->var->arg); +} + 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); @@ -329,13 +456,13 @@ static inline void psi_do_free(free_stmt *fre) } /* FIXME: check in validate_* that free functions return scalar */ - PSI_ContextCall(&PSI_G(context), &f->decl->call, NULL); + psi_context_call(&PSI_G(context), &f->decl->call, NULL); } } -static inline void psi_clean_array_struct(let_stmt *let, decl_arg *darg) { - if (let->val->kind == PSI_LET_FUNC - && let->val->data.func->type == PSI_T_ARRVAL) { +static inline void psi_clean_array_struct(let_val *val, decl_arg *darg) { + if (val->kind == PSI_LET_FUNC + && val->data.func->type == PSI_T_ARRVAL) { decl_type *type = real_decl_type(darg->type); if (type->type == PSI_T_STRUCT) { @@ -344,6 +471,59 @@ static inline void psi_clean_array_struct(let_stmt *let, decl_arg *darg) { while (*ptr) { efree(*ptr++); } + // args = type->real.strct->args; + } else if (type->type == PSI_T_UNION) { + void **ptr = (void **) ((char *) darg->mem + type->real.unn->size); + + if (*ptr) { + efree(*ptr); + } + // args = type->real.unn->args; + } +#if 0 + if (args && val->data.func->inner) { + size_t i; + + for (i = 0; i < val->data.func->inner->count; ++i) { + let_val *inner = val->data.func->inner->vals[i]; + decl_var *refvar = locate_let_val_inner_ref(inner)->var; + decl_arg *subarg = locate_decl_arg(args, refvar->name); + + if (subarg) { + psi_clean_array_struct(val->data.func->inner->vals[i], subarg); + if (subarg->mem) { + efree(subarg->mem); + subarg->mem = NULL; + } + } + } + } +#endif + } +} + +static inline void psi_clean_let_val(let_val *val) { + + let_func *func = locate_let_val_func(val); + + if (func && func->inner) { + size_t i; + + for (i = 0; i < func->inner->count; ++i) { + let_val *inner = func->inner->vals[i]; + psi_clean_let_val(inner); + } + } + if (val->var) { + decl_arg *darg = val->var->arg; + if (darg) { + if (darg->mem) { + psi_clean_array_struct(val, darg); + efree(darg->mem); + darg->mem = NULL; + } + darg->ptr = &darg->val; + darg->let = darg->ptr; } } } @@ -379,15 +559,7 @@ static inline void psi_do_clean(impl *impl) for (i = 0; i < impl->stmts->let.count; ++i) { let_stmt *let = impl->stmts->let.list[i]; - decl_arg *darg = let->var->arg; - - if (darg->mem) { - psi_clean_array_struct(let, darg); - efree(darg->mem); - darg->mem = NULL; - } - darg->ptr = &darg->val; - darg->let = darg->ptr; + psi_clean_let_val(let->val); } if (impl->func->args->vararg.args) { @@ -423,11 +595,16 @@ static inline void psi_do_args(impl *impl) { } if (!impl->decl->func->var->pointer_level) { - decl_type *real = real_decl_type(impl->decl->func->type); + decl_type *real; + decl_args *args = extract_decl_type_args(impl->decl->func->type, &real); switch (real->type) { case PSI_T_STRUCT: - impl->decl->func->ptr = psi_array_to_struct(real->real.strct, NULL); + case PSI_T_UNION: + impl->decl->func->ptr = ecalloc(1, + extract_decl_type_size(real, NULL) + args->count * sizeof(void*)); + break; + default: break; } } @@ -450,7 +627,7 @@ static inline impl_vararg *psi_do_varargs(impl *impl) { impl_arg *vaarg = va->args->args[i]; void *to_free = NULL; token_t vatype = va->name->type->type; - let_func_handler let_fn; + psi_marshal_let let_fn; if (vatype == PSI_T_MIXED) { switch (Z_TYPE_P(vaarg->_zv)) { @@ -476,7 +653,7 @@ static inline impl_vararg *psi_do_varargs(impl *impl) { /* FIXME: varargs with struct-by-value :) */ //if (!psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free)) { - if (!let_fn(&va->values[i], NULL, vaarg, &to_free)) { + if (!let_fn(&va->values[i], NULL, vaarg->type->type, &vaarg->val, vaarg->_zv, &to_free)) { return NULL; } @@ -520,7 +697,7 @@ ZEND_RESULT_CODE psi_call(zend_execute_data *execute_data, zval *return_value, i } } - PSI_ContextCall(&PSI_G(context), &impl->decl->call, va); + psi_context_call(&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) { @@ -565,7 +742,7 @@ ZEND_RESULT_CODE psi_callback(let_callback *cb, void *retval, unsigned argc, voi iarg->_zv = &return_value; zend_fcall_info_call(&iarg->val.zend.cb->fci, &iarg->val.zend.cb->fcc, iarg->_zv, NULL); - /* marshal return value of the userland call */ + /* marshal return value of the userland call switch (iarg->type->type) { case PSI_T_BOOL: zend_parse_arg_bool(iarg->_zv, &iarg->val.zend.bval, NULL, 0); break; case PSI_T_LONG: zend_parse_arg_long(iarg->_zv, &iarg->val.zend.lval, NULL, 0, 1); break; @@ -573,7 +750,9 @@ ZEND_RESULT_CODE psi_callback(let_callback *cb, void *retval, unsigned argc, voi case PSI_T_DOUBLE: zend_parse_arg_double(iarg->_zv, &iarg->val.dval, NULL, 0); break; case PSI_T_STRING: zend_parse_arg_str(iarg->_zv, &iarg->val.zend.str, 0); break; } - result = cb->func->handler(retval, decl_cb->func->type, iarg, &to_free); + */ + result = psi_let_func_ex(cb->func, retval, decl_cb->func->type, decl_cb->func->var, 0, &iarg->val, iarg->_zv, &to_free); + // result = cb->func->handler(retval, decl_cb->func->type, iarg, &to_free); if (result != retval) { *(void **)retval = result;