From: Michael Wallner Date: Thu, 21 Jan 2016 08:59:52 +0000 (+0100) Subject: passing structs by value X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=commitdiff_plain;h=77a446cbcdce6558c00066e5f13e43e8b1b18ff7 passing structs by value --- diff --git a/config.m4 b/config.m4 index 9cd22a3..9666b1b 100644 --- a/config.m4 +++ b/config.m4 @@ -33,6 +33,7 @@ m4_foreach(incfile, [ [sys_types.m4], [sys_uio.m4], [sys_utsname.m4], + [ndbm.m4], [netdb.m4], [netinet_in.m4], [netinet_tcp.m4], @@ -75,6 +76,7 @@ if test "$PHP_PSI" != no; then PSI_CHECK_SYS_STAT PSI_CHECK_SYS_UIO PSI_CHECK_SYS_UTSNAME + PSI_CHECK_NDBM PSI_CHECK_NETDB PSI_CHECK_NETINET_IN PSI_CHECK_NETINET_TCP diff --git a/m4/psi.m4 b/m4/psi.m4 index ae6c81a..3853fa6 100644 --- a/m4/psi.m4 +++ b/m4/psi.m4 @@ -100,6 +100,9 @@ AC_DEFUN(PSI_INCLUDES, [AC_INCLUDES_DEFAULT() #ifdef HAVE_ARPA_NAMESER_H # include #endif +#ifdef HAVE_NDBM_H +# include +#endif #ifdef HAVE_NETDB_H # include #endif diff --git a/m4/psi_const.m4 b/m4/psi_const.m4 index 71adb03..6b86d11 100644 --- a/m4/psi_const.m4 +++ b/m4/psi_const.m4 @@ -1,13 +1,13 @@ # psi_add_str_const(name, value) # Add a pre-defined string constant to $PSI_CONSTS psi_add_str_const() { - cat >>$PSI_CONSTS <<<" {PSI_T_STRING, \"string\", \"psi\\\\$1\", $2, PSI_T_QUOTED_STRING}, " + grep -q "\"psi\\\\\\\\$1\"" $PSI_CONSTS || cat >>$PSI_CONSTS <<<" {PSI_T_STRING, \"string\", \"psi\\\\$1\", $2, PSI_T_QUOTED_STRING}, " } # psi_add_int_const(name, value) # Add a pre-defined int constant to $PSI_CONSTS psi_add_int_const() { - cat >>$PSI_CONSTS <<<" {PSI_T_INT, \"int\", \"psi\\\\$1\", \"$2\", PSI_T_NUMBER}, " + grep -q "\"psi\\\\\\\\$1\"" $PSI_CONSTS || cat >>$PSI_CONSTS <<<" {PSI_T_INT, \"int\", \"psi\\\\$1\", \"$2\", PSI_T_NUMBER}, " } dnl PSI_CONST(const name, type) diff --git a/m4/psi_type.m4 b/m4/psi_type.m4 index dad3b67..2936ef1 100644 --- a/m4/psi_type.m4 +++ b/m4/psi_type.m4 @@ -36,7 +36,7 @@ dnl "uint"), AX_CHECK_SIGN is used to discover signedness of the type. dnl Defines a pre-defined type in $PSI_TYPES. AC_DEFUN(PSI_TYPE, [ ifdef(AS_TR_CPP(AC_TYPE_$1), AS_TR_CPP(AC_TYPE_$1)) - PSI_CHECK_SIZEOF($1, PSI_INCLUDES) + PSI_CHECK_SIZEOF($1) psi_basic_type=AS_TR_SH($2) case $psi_basic_type in int) @@ -60,7 +60,7 @@ dnl Defines a pre-defined type in $PSI_TYPES and a pre-defined struct in dnl $PSI_STRUCTS if the type is a struct. AC_DEFUN(PSI_OPAQUE_TYPE, [ ifdef(AS_TR_CPP(AC_TYPE_$1), AS_TR_CPP(AC_TYPE_$1)) - PSI_CHECK_SIZEOF($1, PSI_INCLUDES) + PSI_CHECK_SIZEOF($1) if PSI_SH_TEST_SIZEOF($1); then psi_type_class= AC_CACHE_CHECK(type class of $1, AS_TR_SH([psi_cv_type_class_]$1), [ diff --git a/psi.d/glob.psi b/psi.d/glob.psi index ce6f5a7..72c0c76 100644 --- a/psi.d/glob.psi +++ b/psi.d/glob.psi @@ -2,7 +2,7 @@ function psi\glob(string $pattern, int $flags, array &$glob = NULL) : int { let path = strval($pattern); let flags = intval($flags); let err = NULL; - let buf = arrval($glob); + let buf = &arrval($glob); return to_int(glob); set $glob = to_array(*buf, to_int(gl_matchc), diff --git a/psi.d/netdb.psi b/psi.d/netdb.psi index 259fcec..2b74b2d 100644 --- a/psi.d/netdb.psi +++ b/psi.d/netdb.psi @@ -47,7 +47,7 @@ function psi\gai_strerror(int $errcode) : string { function psi\getaddrinfo(string $node, string $service, array $hints, object &$res = NULL) : int { let node = strval($node); let service = strval($service); - let hints = arrval($hints); + let hints = &arrval($hints); let res = &NULL; return to_int(getaddrinfo); set $res = to_array(**res, @@ -60,7 +60,7 @@ function psi\getaddrinfo(string $node, string $service, array $hints, object &$r to_string(ai_canonname), to_array(*ai_next, ...) ); - free freeaddrinfo(res); + free freeaddrinfo(*res); } // extern int getnameinfo(struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags) diff --git a/psi.d/time.psi b/psi.d/time.psi index ff81e93..13959da 100644 --- a/psi.d/time.psi +++ b/psi.d/time.psi @@ -18,13 +18,13 @@ function psi\gettimeofday(array &$tv = NULL, array &$tz = NULL) : int { // extern char *asctime(struct tm *tm); function psi\asctime(array $tm = NULL) : string { - let tm = arrval($tm); + let tm = &arrval($tm); return to_string(asctime); } // extern char *asctime_r(struct tm *tm, char *buf); function psi\asctime_r(array $tm = NULL) : string { - let tm = arrval($tm); + let tm = &arrval($tm); let buf = calloc(32, psi\SIZEOF_CHAR); return to_string(asctime_r); } @@ -64,7 +64,7 @@ function psi\gmtime_r(int $ts) : array { // extern int nanosleep(struct timespec *rqts, struct timespec *rmts); function psi\nanosleep(array $rq = NULL, array &$rm = NULL) : int { - let rqts = arrval($rq); + let rqts = &arrval($rq); let rmts = calloc(1, psi\SIZEOF_STRUCT_TIMESPEC); return to_int(nanosleep); set $rm = to_array(*rmts, diff --git a/src/libffi.c b/src/libffi.c index 44c591b..d59712c 100644 --- a/src/libffi.c +++ b/src/libffi.c @@ -160,10 +160,10 @@ static ffi_type **psi_ffi_struct_type_elements(decl_struct *strct) { ZEND_ASSERT(nels + 1 < argc); els[nels++] = type; - +//fprintf(stderr, "%s o:%d, a:%d, p:%d l:%d\n", darg->var->name, offset, align, padding, darg->layout->len); offset += MAX(align, padding) + darg->layout->len; } - +//fprintf(stderr, "%s s:%d o=%d\n", strct->name, strct->size, offset); ZEND_ASSERT(offset <= strct->size); if (offset < strct->size) { padding = strct->size - offset; @@ -186,7 +186,7 @@ static inline ffi_type *psi_ffi_decl_type(decl_type *type) { ffi_type *strct = calloc(1, sizeof(ffi_type)); strct->type = FFI_TYPE_STRUCT; - strct->size = real->strct->size; + strct->size = 0;//real->strct->size; strct->elements = psi_ffi_struct_type_elements(real->strct); real->strct->engine.type = strct; diff --git a/src/module.c b/src/module.c index 5c8634a..3e95970 100644 --- a/src/module.c +++ b/src/module.c @@ -23,6 +23,8 @@ # define PSI_ENGINE "ffi" #endif +#include + ZEND_DECLARE_MODULE_GLOBALS(psi); PHP_INI_BEGIN() @@ -350,6 +352,7 @@ void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp) 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) { @@ -609,7 +612,7 @@ static inline void *psi_do_calloc(let_calloc *alloc) return mem; } -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) +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: @@ -651,7 +654,7 @@ static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, imp if (PSI_T_PATHVAL == let_func) { if (SUCCESS != php_check_open_basedir(arg_val->ptr)) { efree(arg_val->ptr); - return FAILURE; + return NULL; } } break; @@ -670,8 +673,8 @@ static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, imp break; case PSI_T_ARRVAL: if (iarg->type->type == PSI_T_ARRAY) { - arg_val->ptr = psi_array_to_struct(strct, HASH_OF(iarg->_zv)); - *to_free = arg_val->ptr; + arg_val = psi_array_to_struct(strct, HASH_OF(iarg->_zv)); + *to_free = arg_val; } break; case PSI_T_OBJVAL: @@ -679,7 +682,7 @@ static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, imp psi_object *obj; if (!instanceof_function(Z_OBJCE_P(iarg->_zv), psi_class_entry)) { - return FAILURE; + return NULL; } obj = PSI_OBJ(iarg->_zv, NULL); @@ -688,7 +691,7 @@ static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, imp break; EMPTY_SWITCH_DEFAULT_CASE(); } - return SUCCESS; + return arg_val; } static inline void *psi_do_let(let_stmt *let) @@ -724,7 +727,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, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem)) { + if (!(darg->ptr = psi_let_val(let->val->data.func->type, iarg, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem))) { return NULL; } } @@ -759,8 +762,9 @@ static inline void psi_do_free(free_stmt *fre) 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] = &darg->val; + f->decl->call.args[j] = deref_impl_val(fval, dvar); } /* FIXME: check in validate_* that free functions return scalar */ @@ -812,6 +816,7 @@ static inline void psi_do_clean(impl *impl) efree(darg->mem); darg->mem = NULL; } + darg->ptr = &darg->val; } if (impl->func->args->vararg.args) { @@ -1123,7 +1128,10 @@ static inline impl_vararg *psi_do_varargs(impl *impl) { } va->types[i] = vatype; - psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free); + /* 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) { diff --git a/src/parser.h b/src/parser.h index d5ff896..19bea06 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1213,7 +1213,7 @@ static inline impl_val *enref_impl_val(void *ptr, decl_var *var) { var->name, var->pointer_level, var->arg->var->pointer_level, var->array_size, var->arg->var->array_size); #endif - if (!var->pointer_level && real_decl_type(var->arg->type)->type != PSI_T_STRUCT) { + if (!var->pointer_level ){//&& real_decl_type(var->arg->type)->type != PSI_T_STRUCT) { return ptr; } diff --git a/tests/idn/idn.psi b/tests/idn/idn.psi index 2bed911..7c585b7 100644 --- a/tests/idn/idn.psi +++ b/tests/idn/idn.psi @@ -27,7 +27,7 @@ function idn\utf8_to_ascii(string $host, string &$result, int $flags = 0) : int let flags = intval($flags); set $result = to_string(*buffer); return to_int(idna_to_ascii_8z); - free free(buffer); + free free(*buffer); } default char *idna_strerror(int rc); function idn\strerror(int $rc) : string { diff --git a/tests/ndbm/ndbm.psi b/tests/ndbm/ndbm.psi new file mode 100644 index 0000000..e61ba2d --- /dev/null +++ b/tests/ndbm/ndbm.psi @@ -0,0 +1,28 @@ +function psi\dbm_open(string $file, int $open_flags, int $file_mode) : object { + let file = pathval($file); + let open_flags = intval($open_flags); + let file_mode = intval($file_mode); + return to_object(dbm_open); +} + +function psi\dbm_store(object $db, array $key, array $data, int $mode) : int { + let db = objval($db); + let key = arrval($key); + let content = arrval($data); + let store_mode = intval($mode); + return to_int(dbm_store); +} + +function psi\dbm_fetch(object $db, array $key) : array { + let db = objval($db); + let key = arrval($key); + return to_array(dbm_fetch, + to_string(dptr, dsize), + to_int(dsize) + ); +} + +function psi\dbm_close(object $db) : void { + let db = objval($db); + return void(dbm_close); +} diff --git a/tests/ndbm/ndbm001.phpt b/tests/ndbm/ndbm001.phpt new file mode 100644 index 0000000..e14f3f1 --- /dev/null +++ b/tests/ndbm/ndbm001.phpt @@ -0,0 +1,59 @@ +--TEST-- +ndbm +--INI-- +psi.directory={PWD}:{PWD}/../../psi.d +--SKIPIF-- + +--FILE-- +===TEST=== +db = psi\dbm_open($file, $o, $m)) { + throw new Exception(psi\strerror(psi\errno())); + } + } + + function __destruct() { + psi\dbm_close($this->db); + } + + function __set($k, $v) { + return psi\dbm_store($this->db, [ + "dptr" => $k, + "dsize" => strlen($k) + ], [ + "dptr" => $v, + "dsize" => strlen($v) + ], psi\DBM_REPLACE); + } + + function __get($k) { + $val = psi\dbm_fetch($this->db, [ + "dptr" => $k, + "dsize" => strlen($k) + ]); + if ($val) { + return $val["dptr"]; + } + } +} + +$db = new db(); +$db->key = "data"; +var_dump($db->key); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +===TEST=== +string(4) "data" +===DONE===