From: Michael Wallner Date: Wed, 10 Feb 2016 14:39:01 +0000 (+0100) Subject: flush X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=commitdiff_plain;h=8d2ff6a3b85203ea5f8398f846a7764fd0e1d126 flush --- diff --git a/src/context_dump.c b/src/context_dump.c index b778525..8e11eca 100644 --- a/src/context_dump.c +++ b/src/context_dump.c @@ -127,10 +127,10 @@ static inline void dump_impl_set_value(int fd, set_value *set, unsigned level, i dprintf(fd, ", "); dump_num_exp(fd, set->num); } - if (set->inner && set->func->type != PSI_T_ELLIPSIS) { + if (set->inner && set->inner->vals && 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)); + for (i = 0; i < set->inner->count; ++i) { + dump_impl_set_value(fd, set->inner->vals[i], level+1, i == (set->inner->count - 1)); } /* only if inner stmts, i.e. with new lines, were dumped */ dump_level(fd, level); diff --git a/src/context_validate.c b/src/context_validate.c index 45e2d98..56d7b2e 100644 --- a/src/context_validate.c +++ b/src/context_validate.c @@ -721,7 +721,6 @@ static inline int validate_set_value_handler(set_value *set) { 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 */ @@ -766,7 +765,7 @@ static inline int validate_set_value_ex(PSI_Data *data, set_value *set, decl_arg } ref_type = real_decl_type(ref->type); - if (set->count) { + if (set->inner && set->inner->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); @@ -784,21 +783,21 @@ static inline int validate_set_value_ex(PSI_Data *data, set_value *set, decl_arg 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]; + if (!set->outer.set || set->outer.set->inner->vals != set->inner->vals) { + for (i = 0; i < set->inner->count; ++i) { + decl_var *sub_var = set->inner->vals[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)) { + if (!validate_set_value_ex(data, set->inner->vals[i], sub_ref, ref_type->strct->args)) { return 0; } } } } - } else if (set->count == 1) { + } else if (set->inner && set->inner->count == 1) { /* to_array(ptr, to_string(*ptr)) */ - decl_var *sub_var = set->inner[0]->vars->vars[0]; + decl_var *sub_var = set->inner->vals[0]->vars->vars[0]; decl_arg *sub_ref = locate_decl_var_arg(sub_var, ref_list, ref); if (sub_ref) { @@ -806,11 +805,11 @@ static inline int validate_set_value_ex(PSI_Data *data, set_value *set, decl_arg data->error(data, 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)) { + if (!validate_set_value_ex(data, set->inner->vals[0], sub_ref, ref_list)) { return 0; } } - } else if (set->count > 1) { + } else if (set->inner && set->inner->count > 1) { data->error(data, set->func->token, E_WARNING, "Inner `set` statement casts on pointers may only occur once"); return 0; } @@ -883,6 +882,52 @@ static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) { return 1; } +static inline int validate_let_func(PSI_Data *data, let_func *func, impl *impl) { + int check = 0; + size_t j; + + if (impl->func->args) { + for (j = 0; j < impl->func->args->count; ++j) { + impl_arg *iarg = impl->func->args->args[j]; + + if (!strcmp(func->var->name, iarg->var->name)) { + func->arg = iarg; + check = 1; + break; + } + } + } + if (!check) { + data->error(data, func->var->token, PSI_WARNING, "Unknown value '$%s' of `let` statement" + " for cast '%s' of implementation '%s'", + func->var->name, func->name, impl->func->name); + return 0; + } + return 1; +} + +static inline int validate_let_callback(PSI_Data *data, decl_var *let_var, let_callback *cb, impl *impl) { + decl_type *cb_type; + decl *cb_func; + size_t i; + + if (!validate_let_func(data, cb->func, impl)) { + return 0; + } + + cb_type = real_decl_type(let_var->arg->type); + if (cb_type->type != PSI_T_FUNCTION) { + data->error(data, let_var->token, PSI_WARNING, "Not a function: %s", let_var->name); + return 0; + } + cb_func = cb_type->func; + for (i = 0; i < cb->args->count; ++i) { + if (!validate_set_value(data, cb->args->vals[i], cb_func->args->count, cb_func->args->args, 0)) { + return 0; + } + } +} + static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) { size_t i, j; /* we can have multiple let stmts */ @@ -934,22 +979,13 @@ static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) { 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; - } - } + case PSI_LET_CALLBACK: + if (!validate_let_callback(data, let->var, let->val->data.callback, impl)) { + return 0; } - if (!check) { - data->error(data, 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); + break; + case PSI_LET_FUNC: + if (!validate_let_func(data, let->val->data.func, impl)) { return 0; } break; diff --git a/src/engine.c b/src/engine.c index a86cd0b..3a14e6d 100644 --- a/src/engine.c +++ b/src/engine.c @@ -194,7 +194,16 @@ static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, i } else if (PSI_T_MIXED == iarg->type->type) { Z_PARAM_PROLOGUE(0); } else if (PSI_T_CALLABLE == iarg->type->type) { - Z_PARAM_FUNC_EX(iarg->val.zend.cb.fci, iarg->val.zend.cb.fcc, 1, 0); + zend_fcall_info fci; + zend_fcall_info_cache fcc; + + Z_PARAM_FUNC_EX(fci, fcc, 1, 0); + + if (fci.size) { + iarg->val.zend.cb = calloc(1, sizeof(zend_fcall)); + iarg->val.zend.cb->fci = fci; + iarg->val.zend.cb->fcc = fcc; + } } else { error_code = ZPP_ERROR_FAILURE; break; @@ -325,7 +334,7 @@ static inline impl_val *psi_let_val(token_t let_func, impl_arg *iarg, impl_val * arg_val->ptr = obj->data; } break; - case PSI_T_CBVAL: + case PSI_T_CALLBACK: if (iarg->type->type == PSI_T_CALLABLE) { } @@ -362,6 +371,9 @@ static inline void *psi_do_let(let_stmt *let) arg_val->ptr = psi_do_calloc(let->val->data.alloc); darg->mem = arg_val->ptr; break; + case PSI_LET_CALLBACK: + arg_val->ptr = 0 /* callback closure */; + break; case PSI_LET_NUMEXP: arg_val->zend.lval = psi_long_num_exp(let->val->data.num, NULL); break; @@ -380,14 +392,6 @@ static inline void *psi_do_let(let_stmt *let) } } -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); diff --git a/src/engine.h b/src/engine.h index 364ec55..83f64f1 100644 --- a/src/engine.h +++ b/src/engine.h @@ -16,6 +16,14 @@ static inline size_t psi_offset_padding(size_t diff, size_t alignment) { return diff; } +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); +} + int psi_internal_type(impl_type *type); zend_internal_arg_info *psi_internal_arginfo(impl *impl); size_t psi_num_min_args(impl *impl); diff --git a/src/libffi.c b/src/libffi.c index 13eab49..72ebbf0 100644 --- a/src/libffi.c +++ b/src/libffi.c @@ -81,17 +81,24 @@ static void psi_ffi_callback(ffi_cif *_sig, void *_result, void **_args, void *_ unsigned argc = _sig->nargs; void **argv = _args; ffi_arg *res = _result; - decl *decl = _data; - size_t i; + let_stmt *let; + decl_arg *darg = let->var->arg; + decl *decl_cb = darg->type->func; + let_callback *cb = let->val->data.callback; + impl_arg *iarg = cb->func->arg; + size_t i, argc = cb->args->count; + zval *argv = calloc(argc, sizeof(*argv)); // prepare args for the userland call - for (i = 0; i < decl->args->count; ++i) { + for (i = 0; i < decl_cb->args->count; ++i) { } - // marshal return value of the userland call - switch (decl->func->type->type) { - + for (i = 0; i < cb->args->count; ++i) { + psi_do_set(&argv[i], cb->args->vals[i]); } + zend_fcall_info_argp(iarg->val.zend.cb->fci, argc, argv); + // marshal return value of the userland call + darg->ptr = psi_let_val(cb->func->type, iarg, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem); } static inline ffi_type *psi_ffi_decl_arg_type(decl_arg *darg); @@ -286,8 +293,9 @@ static inline ffi_type *psi_ffi_decl_type(decl_type *type) { PSI_LibffiCall *call = PSI_LibffiCallAlloc(&PSI_G(context), real->func); ffi_status rc; - rc = psi_ffi_prep_closure(&real->func->call.closure.data, &real->func->call.sym, - &call->signature, psi_ffi_handler, NULL); + rc = psi_ffi_prep_closure( + (void *) &real->func->call.closure.data, + &real->func->call.sym, &call->signature, psi_ffi_handler, NULL); if (FFI_OK == rc) { real->func->call.info = call; real->func->call.closure.dtor = psi_ffi_closure_free; diff --git a/src/marshal.c b/src/marshal.c index c75a358..95ea6d9 100644 --- a/src/marshal.c +++ b/src/marshal.c @@ -248,10 +248,10 @@ void psi_to_array(zval *return_value, set_value *set, impl_val *r_val) if (t == PSI_T_STRUCT) { // decl_struct *s = real_decl_type(var->arg->type)->strct; - if (set->count) { + if (set->inner && set->inner->count) { /* explicit member casts */ - for (i = 0; i < set->count; ++i) { - set_value *sub_set = set->inner[i]; + for (i = 0; i < set->inner->count; ++i) { + set_value *sub_set = set->inner->vals[i]; decl_var *sub_var = sub_set->vars->vars[0]; sub_set->outer.val = ret_val; @@ -301,7 +301,7 @@ void psi_to_array(zval *return_value, set_value *set, impl_val *r_val) 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]; + set_value *sub_set = set->inner->vals[0]; sub_set->outer.val = set->outer.val; for (i = 0; i < n; ++i) { @@ -314,7 +314,7 @@ void psi_to_array(zval *return_value, set_value *set, impl_val *r_val) 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]; + set_value *sub_set = set->inner->vals[0]; sub_set->outer.val = set->outer.val; while (*(void **) ptr) { diff --git a/src/parser.h b/src/parser.h index 820f445..3a00d6d 100644 --- a/src/parser.h +++ b/src/parser.h @@ -30,6 +30,11 @@ typedef struct PSI_Token { static inline PSI_Token *PSI_TokenCopy(PSI_Token *src); +typedef struct zend_fcall { + zend_fcall_info fci; + zend_fcall_info_cache fcc; +} zend_fcall; + typedef union impl_val { char cval; int8_t i8; @@ -52,10 +57,7 @@ typedef union impl_val { zend_bool bval; zend_long lval; zend_string *str; - struct { - zend_fcall_info *fci; - zend_fcall_info_cache *fcc; - } cb; + zend_fcall *cb; } zend; void *ptr; uint8_t _dbg[sizeof(void *)]; @@ -489,6 +491,17 @@ static inline impl_var *init_impl_var(const char *name, int is_reference) { return var; } +static inline impl_var *copy_impl_var(impl_var *var) { + impl_var *cpy = malloc(sizeof(*cpy)); + + memcpy(cpy, var, sizeof(*cpy)); + cpy->name = strdup(cpy->name); + if (cpy->token) { + cpy->token = PSI_TokenCopy(cpy->token); + } + return cpy; +} + static inline void free_impl_var(impl_var *var) { if (var->token) { free(var->token); @@ -886,12 +899,32 @@ static inline void free_let_calloc(let_calloc *alloc) { free(alloc); } +typedef struct let_callback { + struct let_func *func; + struct set_values *args; +} let_callback; + +static inline void free_let_func(struct let_func *func); +static inline void free_set_values(struct set_values *vals); +static inline let_callback *init_let_callback(struct let_func *func, struct set_values *args) { + let_callback *cb = calloc(1, sizeof(*cb)); + + cb->func = func; + cb->args = args; + return cb; +} + +static inline void free_let_callback(let_callback *cb) { + free_let_func(cb->func); + free_set_values(cb->args); + free(cb); +} + typedef struct let_func { token_t type; char *name; impl_var *var; impl_arg *arg; - set_values *callback; } let_func; static inline let_func *init_let_func(token_t type, const char *name, impl_var *var) { @@ -914,12 +947,14 @@ typedef struct let_val { PSI_LET_NULL, PSI_LET_NUMEXP, PSI_LET_CALLOC, + PSI_LET_CALLBACK, PSI_LET_FUNC, PSI_LET_TMP, } kind; union { num_exp *num; let_calloc *alloc; + let_callback *callback; let_func *func; decl_var *var; } data; @@ -942,6 +977,9 @@ static inline let_val *init_let_val(enum let_val_kind kind, void *data) { case PSI_LET_CALLOC: let->data.alloc = data; break; + case PSI_LET_CALLBACK: + let->data.callback = data; + break; case PSI_LET_FUNC: let->data.func = data; break; @@ -963,6 +1001,9 @@ static inline void free_let_val(let_val *let) { case PSI_LET_CALLOC: free_let_calloc(let->data.alloc); break; + case PSI_LET_CALLBACK: + free_let_callback(let->data.callback); + break; case PSI_LET_FUNC: free_let_func(let->data.func); break; @@ -1031,10 +1072,15 @@ typedef struct set_value { struct set_value *set; impl_val *val; } outer; - struct set_value **inner; - size_t count; + struct set_values *inner; } set_value; +typedef struct set_values { + set_value **vals; + size_t count; +} set_values; + + static inline set_value *init_set_value(set_func *func, decl_vars *vars) { set_value *val = calloc(1, sizeof(*val)); val->func = func; @@ -1042,8 +1088,8 @@ static inline set_value *init_set_value(set_func *func, decl_vars *vars) { return val; } static inline set_value *add_inner_set_value(set_value *val, set_value *inner) { - val->inner = realloc(val->inner, ++val->count * sizeof(*val->inner)); - val->inner[val->count-1] = inner; + val->inner->vals = realloc(val->inner->vals, ++val->inner->count * sizeof(*val->inner->vals)); + val->inner->vals[val->inner->count-1] = inner; inner->outer.set = val; return val; } @@ -1057,10 +1103,10 @@ static inline void free_set_value(set_value *val) { } if (val->inner && (!val->outer.set || val->outer.set->inner != val->inner)) { size_t i; - for (i = 0; i < val->count; ++i) { - free_set_value(val->inner[i]); + for (i = 0; i < val->inner->count; ++i) { + free_set_value(val->inner->vals[i]); } - free(val->inner); + free(val->inner->vals); } if (val->num) { free_num_exp(val->num); @@ -1068,11 +1114,6 @@ static inline void free_set_value(set_value *val) { free(val); } -typedef struct set_values { - set_value **vals; - size_t count; -} set_values; - static inline set_values *init_set_values(set_value *val) { set_values *vals = calloc(1, sizeof(*vals)); if (val) { diff --git a/src/parser_proc.h b/src/parser_proc.h index 04ebb7e..344fdb9 100644 --- a/src/parser_proc.h +++ b/src/parser_proc.h @@ -54,15 +54,15 @@ #define PSI_T_TRUE 54 #define PSI_T_FALSE 55 #define PSI_T_DOLLAR_NAME 56 -#define PSI_T_CBVAL 57 -#define PSI_T_OBJVAL 58 -#define PSI_T_ARRVAL 59 -#define PSI_T_PATHVAL 60 -#define PSI_T_STRLEN 61 -#define PSI_T_STRVAL 62 -#define PSI_T_FLOATVAL 63 -#define PSI_T_INTVAL 64 -#define PSI_T_BOOLVAL 65 +#define PSI_T_OBJVAL 57 +#define PSI_T_ARRVAL 58 +#define PSI_T_PATHVAL 59 +#define PSI_T_STRLEN 60 +#define PSI_T_STRVAL 61 +#define PSI_T_FLOATVAL 62 +#define PSI_T_INTVAL 63 +#define PSI_T_BOOLVAL 64 +#define PSI_T_CALLBACK 65 #define PSI_T_TO_OBJECT 66 #define PSI_T_TO_ARRAY 67 #define PSI_T_TO_STRING 68 diff --git a/src/parser_proc.y b/src/parser_proc.y index 4ae2b33..57fc968 100644 --- a/src/parser_proc.y +++ b/src/parser_proc.y @@ -700,21 +700,6 @@ let_stmt(let) ::= TEMP decl_var(var) EQUALS decl_var(val) EOS. { let = init_let_stmt(var, init_let_val(PSI_LET_TMP, val)); } -%type let_val {let_val*} -%destructor let_val {free_let_val($$);} -let_val(val) ::= NULL. { - val = init_let_val(PSI_LET_NULL, NULL); -} -let_val(val) ::= num_exp(exp). { - val = init_let_val(PSI_LET_NUMEXP, exp); -} -let_val(val) ::= CALLOC LPAREN let_calloc(alloc) RPAREN. { - val = init_let_val(PSI_LET_CALLOC, alloc); -} -let_val(val) ::= let_func(func). { - val = init_let_val(PSI_LET_FUNC, func); -} - %type let_calloc {let_calloc*} %destructor let_calloc {free_let_calloc($$);} let_calloc(alloc) ::= num_exp(nmemb) COMMA num_exp(size). { @@ -727,18 +712,16 @@ let_func(func) ::= let_func_token(T) LPAREN impl_var(var) RPAREN. { func = init_let_func(T->type, T->text, var); free(T); } -let_func(func_) ::= CALLBACK let_func_token(T) LPAREN impl_var(var) callback_arg_list(args_) RPAREN. { - func_ = init_let_func(T->type, T->text, var); - func_->callback.func = func_; - func_->callback.args = args_; - free(T); -} +%type callback_arg_list {set_values *} +%destructor callback_arg_list {free_set_values($$);} callback_arg_list ::= . callback_arg_list(args) ::= COMMA callback_args(args_). { args = args_; } +%type callback_args {set_values *} +%destructor callback_args {free_set_values($$);} callback_args(args) ::= set_value(val). { args = init_set_values(val); } @@ -746,6 +729,26 @@ callback_args(args) ::= callback_args(args_) COMMA set_value(val). { args = add_set_value(args_, val); } +%type let_val {let_val*} +%destructor let_val {free_let_val($$);} +let_val(val) ::= NULL. { + val = init_let_val(PSI_LET_NULL, NULL); +} +let_val(val) ::= num_exp(exp). { + val = init_let_val(PSI_LET_NUMEXP, exp); +} +let_val(val) ::= CALLOC LPAREN let_calloc(alloc) RPAREN. { + val = init_let_val(PSI_LET_CALLOC, alloc); +} +let_val(val) ::= let_func(func). { + val = init_let_val(PSI_LET_FUNC, func); +} +let_val(val) ::= CALLBACK let_func_token(F) LPAREN impl_var(var) callback_arg_list(args_) RPAREN. { + val = init_let_val(PSI_LET_CALLBACK, init_let_callback( + init_let_func(F->type, F->text, var), args_)); + free(F); +} + %type set_stmt {set_stmt*} %destructor set_stmt {free_set_stmt($$);} set_stmt(set) ::= SET impl_var(var) EQUALS set_value(val) EOS. {