flush
authorMichael Wallner <mike@php.net>
Mon, 4 Jan 2016 14:44:41 +0000 (15:44 +0100)
committerMichael Wallner <mike@php.net>
Mon, 4 Jan 2016 14:44:41 +0000 (15:44 +0100)
m4/psi.m4
src/context.c
src/context.h
src/libffi.c
src/libjit.c
src/module.c

index e9955f0..ff483bf 100644 (file)
--- a/m4/psi.m4
+++ b/m4/psi.m4
@@ -77,10 +77,10 @@ AC_DEFUN(PSI_CHECK_LIBJIT, [
        fi
 ])
 
+PHP_ARG_WITH(psi-libffi, where to find libffi,
+[  --with-psi-libffi=DIR   PSI: path to libffi], [ ], [ ])
 AC_DEFUN(PSI_CHECK_LIBFFI, [
        AC_REQUIRE([PSI_PKG_CONFIG])dnl
-       PHP_ARG_WITH(psi-libffi, where to find libffi,
-       [  --with-psi-libffi=DIR   PSI: path to libffi], [ ], [ ])
 
        AC_CACHE_CHECK(for libffi through pkg-config, psi_cv_libffi, [
        if $PKG_CONFIG --exists libffi
index 8492fcd..f580f7f 100644 (file)
@@ -161,11 +161,26 @@ int psi_glob(const char *pattern, int flags,
        return rv;
 }
 
+int psi_printf(const char *fmt, ...) {
+       int rs;
+       char *a1;
+       va_list ap1, ap2;
+
+       va_start(ap1, fmt);
+       va_copy(ap2, ap1);
+       a1 = va_arg(ap2, char *);
+       rs = vprintf(fmt, ap1);
+       va_end(ap1);
+       va_end(ap2);
+       return rs;
+}
+
 static struct psi_func_redir {
        const char *name;
        void (*func)(void);
 } psi_func_redirs[] = {
        {"glob", (void (*)(void)) psi_glob},
+       {"printf", (void (*)(void)) psi_printf},
        PSI_REDIRS
        {0}
 };
@@ -1214,9 +1229,9 @@ zend_function_entry *PSI_ContextCompile(PSI_Context *C)
 }
 
 
-void PSI_ContextCall(PSI_Context *C, decl_callinfo *decl_call)
+void PSI_ContextCall(PSI_Context *C, decl_callinfo *decl_call, impl_vararg *va)
 {
-       C->ops->call(C, decl_call);
+       C->ops->call(C, decl_call, va);
 }
 
 static inline void dump_decl_type(int fd, decl_type *t) {
index 92c9d2c..a010eee 100644 (file)
@@ -14,7 +14,7 @@ struct PSI_ContextOps {
        void (*init)(PSI_Context *C);
        void (*dtor)(PSI_Context *C);
        zend_function_entry *(*compile)(PSI_Context *C);
-       void (*call)(PSI_Context *C, decl_callinfo *decl_call);
+       void (*call)(PSI_Context *C, decl_callinfo *decl_call, impl_vararg *va);
 };
 
 struct PSI_Context {
@@ -30,7 +30,7 @@ PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErr
 void PSI_ContextBuild(PSI_Context *C, const char *path);
 int PSI_ContextValidate(PSI_Context *C, PSI_Parser *P);
 zend_function_entry *PSI_ContextCompile(PSI_Context *C);
-void PSI_ContextCall(PSI_Context *C, decl_callinfo *decl_call);
+void PSI_ContextCall(PSI_Context *C, decl_callinfo *decl_call, impl_vararg *va);
 void PSI_ContextDump(PSI_Context *C, int fd);
 void PSI_ContextDtor(PSI_Context *C);
 void PSI_ContextFree(PSI_Context **C);
index 257fb48..f776fb7 100644 (file)
@@ -93,6 +93,20 @@ static inline ffi_type *psi_ffi_token_type(token_t t) {
                return &ffi_type_double;
        }
 }
+static inline ffi_type *psi_ffi_impl_type(token_t impl_type) {
+       switch (impl_type) {
+       case PSI_T_BOOL:
+               return &ffi_type_sint8;
+       case PSI_T_INT:
+               return &ffi_type_sint64;
+       case PSI_T_STRING:
+               return &ffi_type_pointer;
+       case PSI_T_FLOAT:
+       case PSI_T_DOUBLE:
+               return &ffi_type_double;
+       EMPTY_SWITCH_DEFAULT_CASE();
+       }
+}
 static inline ffi_type *psi_ffi_decl_type(decl_type *type) {
        return psi_ffi_token_type(real_decl_type(type)->type);
 }
@@ -252,10 +266,33 @@ static zend_function_entry *psi_ffi_compile(PSI_Context *C)
        return zfe;
 }
 
-static void psi_ffi_call(PSI_Context *C, decl_callinfo *decl_call) {
+static void psi_ffi_call(PSI_Context *C, decl_callinfo *decl_call, impl_vararg *va) {
        PSI_LibffiCall *call = decl_call->info;
 
-       ffi_call(&call->signature, FFI_FN(decl_call->sym), decl_call->rval, decl_call->args);
+       if (va) {
+               ffi_status rc;
+               ffi_cif signature;
+               size_t i, nfixedargs = decl_call->argc, ntotalargs = nfixedargs + va->args->count;
+               void **params = calloc(2 * ntotalargs + 2, sizeof(void *));
+
+               for (i = 0; i < nfixedargs; ++i) {
+                       params[i] = call->params[i];
+                       params[i + ntotalargs + 1] = call->params[i + nfixedargs + 1];
+               }
+               for (i = 0; i < va->args->count; ++i) {
+                       params[nfixedargs + i] = psi_ffi_impl_type(va->types[i]);
+                       params[nfixedargs + i + ntotalargs + 1] = &va->values[i];
+               }
+
+               rc = ffi_prep_cif_var(&signature, call->signature.abi,
+                               nfixedargs, ntotalargs,
+                               call->signature.rtype, (ffi_type **) params);
+               ZEND_ASSERT(FFI_OK == rc);
+               ffi_call(&signature, FFI_FN(decl_call->sym), decl_call->rval, &params[ntotalargs + 1]);
+               free(params);
+       } else {
+               ffi_call(&call->signature, FFI_FN(decl_call->sym), decl_call->rval, decl_call->args);
+       }
 }
 
 static PSI_ContextOps ops = {
index 13c0aa4..bc24c1a 100644 (file)
@@ -210,7 +210,7 @@ static zend_function_entry *psi_jit_compile(PSI_Context *C)
        return zfe;
 }
 
-static void psi_jit_call(PSI_Context *C, decl_callinfo *decl_call) {
+static void psi_jit_call(PSI_Context *C, decl_callinfo *decl_call, impl_vararg *va) {
        PSI_LibjitCall *call = decl_call->info;
 
        jit_apply(call->signature, decl_call->sym, decl_call->args,
index cf147b6..ff7353a 100644 (file)
@@ -532,6 +532,8 @@ static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, i
                        error_code = ZPP_ERROR_FAILURE;
                        break;
                }
+               iarg->_zv = _arg;
+               ZVAL_DEREF(iarg->_zv);
                if (_i < _num_args) {
                        goto nextarg;
                }
@@ -545,8 +547,6 @@ static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, i
                iarg = impl->func->args->args[i];
 
                if (i < EX_NUM_ARGS()) {
-                       iarg->_zv = ++zarg;
-                       ZVAL_DEREF(iarg->_zv);
                } else if (iarg->def) {
                        switch (iarg->type->type) {
                        case PSI_T_BOOL:
@@ -579,21 +579,6 @@ static inline void *psi_do_calloc(let_calloc *alloc)
        return mem;
 }
 
-static inline token_t psi_let_fn(token_t impl_type) {
-       switch (impl_type) {
-       case PSI_T_BOOL:
-               return PSI_T_BOOLVAL;
-       case PSI_T_INT:
-               return PSI_T_INTVAL;
-       case PSI_T_FLOAT:
-       case PSI_T_DOUBLE:
-               return PSI_T_FLOATVAL;
-       case PSI_T_STRING:
-               return PSI_T_STRVAL;
-       }
-       return 0;
-}
-
 static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, impl_val *arg_val, decl_struct *strct, void **to_free)
 {
        switch (let_func) {
@@ -704,7 +689,7 @@ static inline void *psi_do_let(let_stmt *let)
        case PSI_LET_FUNC:
                iarg = let->val->data.func->arg;
 
-               if (SUCCESS != psi_let_val(let->val->data.func->type, iarg, real_decl_type(darg->type)->strct, darg->ptr, &darg->mem)) {
+               if (SUCCESS != psi_let_val(let->val->data.func->type, iarg, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem)) {
                        return NULL;
                }
        }
@@ -742,7 +727,7 @@ 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);
+               PSI_ContextCall(&PSI_G(context), &f->decl->call, NULL);
        }
 }
 
@@ -779,6 +764,29 @@ static inline void psi_do_clean(impl *impl)
                        darg->mem = NULL;
                }
        }
+
+       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) {
@@ -1015,33 +1023,62 @@ static inline void psi_do_args(impl *impl) {
        }
 }
 
-static inline void psi_do_varargs(impl *impl, void ***free_list) {
+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;
-       void **tmpvals = calloc(vacount, sizeof(*tmpvals));
-       token_t type = psi_let_fn(va->name->type->type);
 
-       va->types = calloc(vacount, sizeof(*va->types));
-       va->values = calloc(vacount, sizeof(*va->values));
+
+       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;
+               psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free);
 
-               psi_let_val(type, vaarg, &va->values[i], NULL, &to_free);
                if (to_free) {
-                       *free_list = realloc(*free_list, (j + 1) * sizeof(*free_list));
-                       (*free_list)[j++] = 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, j;
-       decl_callinfo *call = &impl->decl->call;
-       void **free_list = NULL;
+       size_t i;
+       impl_vararg *va = NULL;
 
        memset(impl->decl->func->ptr, 0, sizeof(impl_val));
 
@@ -1063,15 +1100,11 @@ void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl)
                psi_do_args(impl);
 
                if (impl->func->args->vararg.args) {
-                       call = psi_do_varargs(impl, &free_list);
+                       va = psi_do_varargs(impl);
                }
        }
 
-       if (impl->func->args->vararg.args) {
-               PSI_ContextCallVarargs(&PSI_G(context), &impl->decl->call)
-       } else {
-               PSI_ContextCall(&PSI_G(context), &impl->decl->call);
-       }
+       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) {