flush
authorMichael Wallner <mike@php.net>
Wed, 10 Feb 2016 14:39:01 +0000 (15:39 +0100)
committerMichael Wallner <mike@php.net>
Wed, 10 Feb 2016 14:39:01 +0000 (15:39 +0100)
src/context_dump.c
src/context_validate.c
src/engine.c
src/engine.h
src/libffi.c
src/marshal.c
src/parser.h
src/parser_proc.h
src/parser_proc.y

index b778525c93a4f4aa76bf9df59a2240933da73036..8e11eca41763589155de8a03fed85780aa463a01 100644 (file)
@@ -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);
index 45e2d987efba15185e435cae228ae99b3fef9d3d..56d7b2ea43eab6caad086c2cdd1dea03be010b09 100644 (file)
@@ -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;
index a86cd0b62460e598d782912cb59dd6368fcbd99d..3a14e6d7e88571c0ff54bad5aa1c22a98eaaad2e 100644 (file)
@@ -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);
index 364ec550fd760350e5d334522b842b8ab6a7f63f..83f64f14b6507b0519a473c1183354cc98b30629 100644 (file)
@@ -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);
index 13eab49d5ecbd958b804cac32525a05c8c968de9..72ebbf095f25482577dbb2bc6618f2b0948f34d8 100644 (file)
@@ -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;
index c75a358bf8d9fbe9622d2d4f5a12645150546b51..95ea6d9b51c103f926b6974bb98baf94342582a0 100644 (file)
@@ -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) {
index 820f44528f9aeae8038a7c1b671a8758738cc591..3a00d6d766a5d75dea7a20fb7380c2aa2aae36c1 100644 (file)
@@ -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) {
index 04ebb7e1c7fb3a6649f809abb3968f8090e17403..344fdb9a9fdf9ceae2eb50124a3593a9639a0817 100644 (file)
 #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
index 4ae2b33d2fe24d3e4967541a6d46c0f3a6410170..57fc968bab2b8226a8e7323cc0864ef3c83a0e26 100644 (file)
@@ -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. {