From 7e5e4c6d2b654cfd3737c37e9e1894be43642721 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 21 Oct 2015 11:34:23 +0200 Subject: [PATCH] flush+ --- Makefile.frag | 4 +- TODO | 1 + php_psi.h | 14 ++ src/context.c | 58 ++++---- src/context.h | 1 - src/libjit.c | 360 +++++++++++----------------------------------- src/module.c | 270 ++++++++++++++++++++++++++++++++++ src/parser.h | 31 ++-- src/parser_proc.y | 7 + 9 files changed, 423 insertions(+), 323 deletions(-) diff --git a/Makefile.frag b/Makefile.frag index d20403f..0f572d1 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -24,12 +24,12 @@ lemon.c: ./lemon: lemon.c | lempar.c $(CC) -o $@ $< -$(PHP_PSI_SRCDIR)/src/parser_proc.y: $(PHP_PSI_SRCDIR)/src/parser.h +$(PHP_PSI_SRCDIR)/src/parser_proc.y: $(PHP_PSI_BUILDDIR)/parser.h touch $@ $(PHP_PSI_SRCDIR)/src/parser_proc.c: $(PHP_PSI_SRCDIR)/src/parser_proc.y $(LEMON) $(LEMON) -c $< -$(PHP_PSI_SRCDIR)/src/parser.re: $(PHP_PSI_SRCDIR)/src/parser.h $(PHP_PSI_SRCDIR)/src/parser_proc.h +$(PHP_PSI_SRCDIR)/src/parser.re: $(PHP_PSI_BUILDDIR)/parser.h $(PHP_PSI_BUILDDIR)/parser_proc.h touch $@ $(PHP_PSI_SRCDIR)/src/parser.c: $(PHP_PSI_SRCDIR)/src/parser.re $(RE2C) -o $@ $< diff --git a/TODO b/TODO index 76fbd27..d658c42 100644 --- a/TODO +++ b/TODO @@ -3,3 +3,4 @@ * let the various list types be hashtables where appropriate * check out jit-dynamic * fix arginfo with nullable types +* pemalloc diff --git a/php_psi.h b/php_psi.h index cce3503..280e786 100644 --- a/php_psi.h +++ b/php_psi.h @@ -20,6 +20,20 @@ extern zend_module_entry psi_module_entry; #endif #include "context.h" +#include "parser.h" + +void psi_error(int type, const char *msg, ...); +int psi_internal_type(impl_type *type); +zend_internal_arg_info *psi_internal_arginfo(impl *impl); +size_t psi_num_min_args(impl *impl); +void psi_to_int(impl_val *ret_val, decl_arg *func, zval *return_value); +void psi_to_string(impl_val *ret_val, decl_arg *func, zval *return_value); +ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl); +impl_val *psi_do_let(decl_arg *darg); +void psi_do_set(zval *return_value, set_func *func, decl_vars *vars); +void psi_do_return(impl *impl, impl_val *ret_val, zval *return_value); +void psi_do_free(free_stmt *fre); +void psi_do_clean(impl *impl); ZEND_BEGIN_MODULE_GLOBALS(psi) char *directory; diff --git a/src/context.c b/src/context.c index 7670462..4939130 100644 --- a/src/context.c +++ b/src/context.c @@ -41,7 +41,6 @@ void PSI_ContextBuild(PSI_Context *C, const char *path) if (n < 0) { return; - C->error(PSI_WARNING, "Failed to scan PSI directory '%s'", path); } else for (i = 0; i < n; ++i) { char psi[MAXPATHLEN]; PSI_Parser P; @@ -71,33 +70,6 @@ void PSI_ContextBuild(PSI_Context *C, const char *path) if (PSI_ValidatorValidate(&V)) { zend_function_entry *closures; - if (V.consts) { - zend_constant zc; - - zc.flags = CONST_PERSISTENT|CONST_CS; - zc.module_number = EG(current_module)->module_number; - - for (i = 0; i < V.consts->count; ++i) { - constant *c = V.consts->list[i]; - - zc.name = zend_string_init(c->name + (c->name[0] == '\\'), strlen(c->name) - (c->name[0] == '\\'), 1); - ZVAL_NEW_STR(&zc.value, zend_string_init(c->val->text, strlen(c->val->text), 1)); - - switch (c->type->type) { - case PSI_T_BOOL: - convert_to_boolean(&zc.value); - break; - case PSI_T_INT: - convert_to_long(&zc.value); - break; - case PSI_T_FLOAT: - convert_to_double(&zc.value); - break; - } - zend_register_constant(&zc); - } - } - closures = PSI_ContextCompile(C, (PSI_Data *) &V); if (closures && SUCCESS != zend_register_functions(NULL, closures, NULL, MODULE_PERSISTENT)) { C->error(PSI_WARNING, "Failed to register functions!"); @@ -116,9 +88,36 @@ void PSI_ContextBuild(PSI_Context *C, const char *path) zend_function_entry *PSI_ContextCompile(PSI_Context *C, PSI_Data *D) { - size_t count = C->count++; + size_t i, count = C->count++; zend_function_entry *zfe; + if (D->consts) { + zend_constant zc; + + zc.flags = CONST_PERSISTENT|CONST_CS; + zc.module_number = EG(current_module)->module_number; + + for (i = 0; i < D->consts->count; ++i) { + constant *c = D->consts->list[i]; + + zc.name = zend_string_init(c->name + (c->name[0] == '\\'), strlen(c->name) - (c->name[0] == '\\'), 1); + ZVAL_NEW_STR(&zc.value, zend_string_init(c->val->text, strlen(c->val->text), 1)); + + switch (c->type->type) { + case PSI_T_BOOL: + convert_to_boolean(&zc.value); + break; + case PSI_T_INT: + convert_to_long(&zc.value); + break; + case PSI_T_FLOAT: + convert_to_double(&zc.value); + break; + } + zend_register_constant(&zc); + } + } + C->data = realloc(C->data, C->count * sizeof(*C->data)); PSI_DataExchange(&C->data[count], D); @@ -139,7 +138,6 @@ void PSI_ContextDtor(PSI_Context *C) for (i = 0; i < C->count; ++i) { PSI_DataDtor(&C->data[i]); if (C->closures[i]){ - free(C->closures[i]->arg_info); free(C->closures[i]); } } diff --git a/src/context.h b/src/context.h index 6e86e44..24bdb9c 100644 --- a/src/context.h +++ b/src/context.h @@ -28,7 +28,6 @@ struct PSI_Context { PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error); void PSI_ContextBuild(PSI_Context *C, const char *path); zend_function_entry *PSI_ContextCompile(PSI_Context *C, PSI_Data *D); -zend_constant a; void PSI_ContextDtor(PSI_Context *C); void PSI_ContextFree(PSI_Context **C); diff --git a/src/libjit.c b/src/libjit.c index 5cc8525..98ce029 100644 --- a/src/libjit.c +++ b/src/libjit.c @@ -1,31 +1,10 @@ #include "php.h" +#include "php_psi.h" #include "libjit.h" -#include "parser_proc.h" -#include "parser.h" #include -static void init(PSI_Context *C) -{ - C->context = jit_context_create(); -} - -static void dtor(PSI_Context *C) -{ - jit_context_destroy(C->context); - C->context = NULL; -} - -static inline size_t impl_num_min_args(impl *impl) { - size_t i, n = impl->func->args->count; - - for (i = 0; i < impl->func->args->count; ++i) { - if (impl->func->args->args[i]->def) { - --n; - } - } - return n; -} +static void handler(jit_type_t _sig, void *result, void **_args, void *_data); static inline jit_abi_t psi_jit_abi(const char *convention) { return jit_abi_cdecl; @@ -80,233 +59,101 @@ static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) { } } -typedef struct PSI_ClosureData { - void *context; +typedef struct PSI_LibjitContext { + jit_context_t jit; + jit_type_t signature; + struct { + struct PSI_LibjitData **list; + size_t count; + } data; +} PSI_LibjitContext; + +typedef struct PSI_LibjitData { + PSI_LibjitContext *context; impl *impl; + zend_internal_arg_info *arginfo; + void *closure; jit_type_t signature; jit_type_t params[1]; -} PSI_ClosureData; +} PSI_LibjitData; -static inline PSI_ClosureData *PSI_ClosureDataAlloc(void *context, impl *impl) { +static inline PSI_LibjitData *PSI_LibjitDataAlloc(PSI_LibjitContext *context, impl *impl) { size_t i, c = impl->decl->args->count; - PSI_ClosureData *data = malloc(sizeof(*data) + (c ? c-1 : c) * sizeof(jit_type_t)); + PSI_LibjitData *data = malloc(sizeof(*data) + (c ? c-1 : c) * sizeof(jit_type_t)); data->context = context; data->impl = impl; + data->arginfo = psi_internal_arginfo(impl); for (i = 0; i < c; ++i) { data->params[i] = psi_jit_decl_arg_type(impl->decl->args->args[i]); } + data->signature = jit_type_create_signature( psi_jit_abi(data->impl->decl->abi->convention), psi_jit_decl_arg_type(data->impl->decl->func), data->params, data->impl->decl->args->count, 1); - return data; -} - - -static inline impl_val *deref(unsigned level, impl_val *ret_val, decl_arg *darg) { - unsigned i; + data->closure = jit_closure_create(context->jit, context->signature, &handler, data); - for (i = level; i < darg->var->pointer_level; ++i && ret_val->ptr) { - ret_val = *(void **)ret_val; - } + context->data.list = realloc(context->data.list, ++context->data.count * sizeof(*context->data.list)); + context->data.list[context->data.count-1] = data; - return ret_val; -} -static void to_int(impl_val *ret_val, decl_arg *func, zval *return_value) { - switch (real_decl_type(func->type)->type) { - case PSI_T_FLOAT: - case PSI_T_DOUBLE: - RETVAL_DOUBLE(deref(0, ret_val, func)->dval); - convert_to_long(return_value); - break; - default: - RETVAL_LONG(deref(0, ret_val, func)->lval); - } -} -static void to_string(impl_val *ret_val, decl_arg *func, zval *return_value) { - switch (real_decl_type(func->type)->type) { - case PSI_T_CHAR: - case PSI_T_SINT8: - case PSI_T_UINT8: - if (!func->var->pointer_level) { - char chr = ret_val->lval; - RETVAL_STRINGL(&chr, 1); - } else { - ret_val = deref(1, ret_val, func); - if (ret_val->ptr) { - RETVAL_STRING(ret_val->ptr); - } else { - RETVAL_EMPTY_STRING(); - } - } - break; - case PSI_T_FLOAT: - case PSI_T_DOUBLE: - RETVAL_DOUBLE(deref(0, ret_val, func)->dval); - convert_to_string(return_value); - break; - default: - RETVAL_LONG(deref(0, ret_val, func)->lval); - convert_to_string(return_value); - break; - } + return data; } -static ZEND_RESULT_CODE handle_args(zend_execute_data *execute_data, impl *impl) { - impl_arg *iarg; - - if (!impl->func->args->count) { - return zend_parse_parameters_none(); - } - - ZEND_PARSE_PARAMETERS_START(impl_num_min_args(impl), impl->func->args->count) - nextarg: - iarg = impl->func->args->args[_i]; - if (iarg->def) { - Z_PARAM_OPTIONAL; - } - if (PSI_T_BOOL == iarg->type->type) { - if (iarg->def) { - iarg->val.cval = iarg->def->type == PSI_T_TRUE ? 1 : 0; - } - Z_PARAM_BOOL(iarg->val.cval); - } else if (PSI_T_INT == iarg->type->type) { - if (iarg->def) { - iarg->val.lval = zend_atol(iarg->def->text, strlen(iarg->def->text)); - } - Z_PARAM_LONG(iarg->val.lval); - } else if (PSI_T_FLOAT == iarg->type->type) { - if (iarg->def) { - iarg->val.dval = zend_strtod(iarg->def->text, NULL); - } - Z_PARAM_DOUBLE(iarg->val.dval); - } else if (PSI_T_STRING == iarg->type->type) { - struct {char *val; size_t len;} str; - if (iarg->def) { - /* FIXME */ - str.len = strlen(iarg->def->text) - 2; - str.val = &iarg->def->text[1]; - } - Z_PARAM_STR_EX(iarg->val.str, 1, 0); - if (iarg->val.str) { - zend_string_addref(iarg->val.str); - } else if (iarg->def) { - iarg->val.str = zend_string_init(str.val, str.len, 0); - } - } else { - error_code = ZPP_ERROR_FAILURE; - break; - } - iarg->_zv = _arg; - if (_i < _max_num_args) { - goto nextarg; - } - ZEND_PARSE_PARAMETERS_END_EX(return FAILURE); - - return SUCCESS; +static inline void PSI_LibjitDataFree(PSI_LibjitData *data) { + free(data->arginfo); + jit_type_free(data->signature); + free(data); } -static impl_val *handle_let(decl_arg *darg, impl_arg *iarg) { - impl_val *arg_val = &darg->let->out; +static inline PSI_LibjitContext *PSI_LibjitContextInit(PSI_LibjitContext *L) { + jit_type_t params[] = { + jit_type_void_ptr, + jit_type_void_ptr + }; - if (!iarg) { - /* let foo = NULL */ - memset(arg_val, 0, sizeof(*arg_val)); - return arg_val; - } - switch (darg->let->val->func->type) { - case PSI_T_BOOLVAL: - if (iarg->type->type == PSI_T_BOOL) { - arg_val->cval = iarg->val.cval; - } else { - arg_val->cval = zend_is_true(iarg->_zv); - } - break; - case PSI_T_INTVAL: - if (iarg->type->type == PSI_T_INT) { - arg_val->lval = iarg->val.lval; - } else { - arg_val->lval = zval_get_long(iarg->_zv); - } - break; - case PSI_T_STRVAL: - if (iarg->type->type == PSI_T_STRING) { - arg_val->ptr = estrdup(iarg->val.str->val); - darg->let->mem = arg_val->ptr; - zend_string_release(iarg->val.str); - } else { - zend_string *zs = zval_get_string(iarg->_zv); - arg_val->ptr = estrdup(zs->val); - darg->let->mem = arg_val->ptr; - zend_string_release(zs); - } - break; - case PSI_T_STRLEN: - if (iarg->type->type == PSI_T_STRING) { - arg_val->lval = iarg->val.str->len; - zend_string_release(iarg->val.str); - } else { - zend_string *zs = zval_get_string(iarg->_zv); - arg_val->lval = zs->len; - zend_string_release(zs); - } - break; - EMPTY_SWITCH_DEFAULT_CASE(); + if (!L) { + L = malloc(sizeof(*L)); } + memset(L, 0, sizeof(*L)); - return arg_val; -} + L->jit = jit_context_create(); + L->signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void, params, 2, 1); -static void handle_rval(impl *impl, impl_val *ret_val, zval *return_value) { - switch (impl->stmts->ret.list[0]->func->type) { - case PSI_T_TO_STRING: - to_string(ret_val, impl->decl->func, return_value); - break; - case PSI_T_TO_INT: - to_int(ret_val, impl->decl->func, return_value); - break; - EMPTY_SWITCH_DEFAULT_CASE(); - } + return L; } -static void handle_set(zval *return_value, set_func *func, decl_vars *vars) { - impl_val *val = &vars->vars[0]->arg->let->ptr; - - ZVAL_DEREF(return_value); - zval_dtor(return_value); +static inline void PSI_LibjitContextDtor(PSI_LibjitContext *L) { + size_t i; - switch (func->type) { - case PSI_T_TO_STRING: - to_string(val, vars->vars[0]->arg, return_value); - break; - EMPTY_SWITCH_DEFAULT_CASE(); + for (i = 0; i < L->data.count; ++i) { + PSI_LibjitDataFree(L->data.list[i]); } + if (L->data.list) { + free(L->data.list); + } + jit_type_free(L->signature); + jit_context_destroy(L->jit); } -static void handle_free(free_stmt *fre) { - size_t i; - - for (i = 0; i < fre->vars->count; ++i) { - decl_var *dvar = fre->vars->vars[i]; - - if (dvar->arg && dvar->arg->let->out.ptr) { - free(dvar->arg->let->out.ptr); - dvar->arg->let->out.ptr = NULL; - } +static inline void PSI_LibjitContextFree(PSI_LibjitContext **L) { + if (*L) { + PSI_LibjitContextDtor(*L); + free(*L); + *L = NULL; } } static void handler(jit_type_t _sig, void *result, void **_args, void *_data) { - PSI_ClosureData *data = _data; + PSI_LibjitData *data = _data; size_t i; void **arg_ptr = NULL, **arg_prm = NULL; impl_val ret_val; - if (SUCCESS != handle_args(*(zend_execute_data **)_args[0], data->impl)) { + if (SUCCESS != psi_parse_args(*(zend_execute_data **)_args[0], data->impl)) { return; } @@ -316,9 +163,8 @@ static void handler(jit_type_t _sig, void *result, void **_args, void *_data) for (i = 0; i < data->impl->decl->args->count; ++i) { decl_arg *darg = data->impl->decl->args->args[i]; - impl_arg *iarg = darg->let ? darg->let->arg : NULL; - arg_ptr[i] = handle_let(darg, iarg); + arg_ptr[i] = psi_do_let(darg); arg_prm[i] = darg->let->val->is_reference ? &arg_ptr[i] : arg_ptr[i]; darg->let->ptr = arg_ptr[i]; @@ -327,111 +173,65 @@ static void handler(jit_type_t _sig, void *result, void **_args, void *_data) jit_apply(data->signature, data->impl->decl->dlptr, arg_prm, data->impl->decl->args->count, &ret_val); - handle_rval(data->impl, &ret_val, *(zval **)_args[1]); + psi_do_return(data->impl, &ret_val, *(zval **)_args[1]); for (i = 0; i < data->impl->stmts->set.count; ++i) { set_stmt *set = data->impl->stmts->set.list[i]; - handle_set(set->arg->_zv, set->val->func, set->val->vars); - } - - if (data->impl->decl->args->count) { - for (i = 0; i < data->impl->decl->args->count; ++i) { - decl_arg *darg = data->impl->decl->args->args[i]; - - if (darg->let && darg->let->mem) { - efree(darg->let->mem); - darg->let->mem = NULL; - } - } - free(arg_ptr); - free(arg_prm); + psi_do_set(set->arg->_zv, set->val->func, set->val->vars); } for (i = 0; i < data->impl->stmts->fre.count; ++i) { free_stmt *fre = data->impl->stmts->fre.list[i]; - handle_free(fre); + psi_do_free(fre); } -} -static inline int fill_type_hint(impl_type *type) { - switch (type->type) { - case PSI_T_BOOL: - return _IS_BOOL; - case PSI_T_INT: - case PSI_T_LONG: - return IS_LONG; - case PSI_T_FLOAT: - case PSI_T_DOUBLE: - return IS_DOUBLE; - case PSI_T_STRING: - return IS_STRING; - case PSI_T_ARRAY: - return IS_ARRAY; - default: - return 0; + psi_do_clean(data->impl); + + if (arg_ptr) { + free(arg_ptr); + } + if (arg_prm) { + free(arg_prm); } } -static inline zend_internal_arg_info *fill_arginfo(impl *impl) { - size_t i; - zend_internal_arg_info *aip; - zend_internal_function_info *fi; - - aip = calloc(impl->func->args->count + 1, sizeof(*aip)); - - fi = (zend_internal_function_info *) &aip[0]; - fi->required_num_args = impl_num_min_args(impl); - fi->return_reference = impl->func->return_reference; - fi->type_hint = fill_type_hint(impl->func->return_type); - - for (i = 0; i < impl->func->args->count; ++i) { - impl_arg *iarg = impl->func->args->args[i]; - zend_internal_arg_info *ai = &aip[i+1]; - - ai->name = iarg->var->name; - ai->type_hint = fill_type_hint(iarg->type); - if (iarg->var->reference) { - ai->pass_by_reference = 1; - } - if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) { - ai->allow_null = 1; - } - } +static void init(PSI_Context *C) +{ + C->context = PSI_LibjitContextInit(NULL); +} - return aip; +static void dtor(PSI_Context *C) +{ + PSI_LibjitContextFree((void *) &C->context); } static zend_function_entry *compile(PSI_Context *C, PSI_Data *D) { size_t i, j = 0; - jit_type_t signature, params[] = { - jit_type_void_ptr, - jit_type_void_ptr - }; zend_function_entry *zfe = calloc(D->impls->count + 1, sizeof(*zfe)); + PSI_LibjitContext *ctx = C->context; - jit_context_build_start(C->context); + jit_context_build_start(ctx->jit); for (i = 0; i < D->impls->count; ++i) { zend_function_entry *zf = &zfe[j]; - PSI_ClosureData *data; + PSI_LibjitData *data; if (!D->impls->list[i]->decl) { continue; } - data = PSI_ClosureDataAlloc(C, D->impls->list[i]); - signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void, params, 2, 1); + data = PSI_LibjitDataAlloc(ctx, D->impls->list[i]); zf->fname = D->impls->list[i]->func->name + (D->impls->list[i]->func->name[0] == '\\'); - zf->handler = jit_closure_create(C->context, signature, &handler, data); zf->num_args = D->impls->list[i]->func->args->count; - zf->arg_info = fill_arginfo(D->impls->list[i]); + zf->handler = data->closure; + zf->arg_info = data->arginfo; ++j; } - jit_context_build_end(C->context); + jit_context_build_end(ctx->jit); return zfe; } diff --git a/src/module.c b/src/module.c index 4df3e11..dba74c5 100644 --- a/src/module.c +++ b/src/module.c @@ -8,6 +8,7 @@ #include "ext/standard/info.h" #include "php_psi.h" +#include "parser.h" #include "libjit.h" @@ -29,6 +30,275 @@ void psi_error(int type, const char *msg, ...) php_error(type, buf); } +int psi_internal_type(impl_type *type) +{ + switch (type->type) { + case PSI_T_BOOL: + return _IS_BOOL; + case PSI_T_INT: + case PSI_T_LONG: + return IS_LONG; + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + return IS_DOUBLE; + case PSI_T_STRING: + return IS_STRING; + case PSI_T_ARRAY: + return IS_ARRAY; + default: + return 0; + } +} + +zend_internal_arg_info *psi_internal_arginfo(impl *impl) +{ + size_t i; + zend_internal_arg_info *aip; + zend_internal_function_info *fi; + + aip = calloc(impl->func->args->count + 1, sizeof(*aip)); + + fi = (zend_internal_function_info *) &aip[0]; + fi->required_num_args = psi_num_min_args(impl); + fi->return_reference = impl->func->return_reference; + fi->type_hint = psi_internal_type(impl->func->return_type); + + for (i = 0; i < impl->func->args->count; ++i) { + impl_arg *iarg = impl->func->args->args[i]; + zend_internal_arg_info *ai = &aip[i+1]; + + ai->name = iarg->var->name; + ai->type_hint = psi_internal_type(iarg->type); + if (iarg->var->reference) { + ai->pass_by_reference = 1; + } + if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) { + ai->allow_null = 1; + } + } + + return aip; +} + +size_t psi_num_min_args(impl *impl) +{ + size_t i, n = impl->func->args->count; + + for (i = 0; i < impl->func->args->count; ++i) { + if (impl->func->args->args[i]->def) { + --n; + } + } + return n; +} + +void psi_to_int(impl_val *ret_val, decl_arg *func, zval *return_value) +{ + switch (real_decl_type(func->type)->type) { + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + RETVAL_DOUBLE(deref_impl_val(0, ret_val, func)->dval); + convert_to_long(return_value); + break; + default: + RETVAL_LONG(deref_impl_val(0, ret_val, func)->lval); + } +} + +void psi_to_string(impl_val *ret_val, decl_arg *func, zval *return_value) +{ + switch (real_decl_type(func->type)->type) { + case PSI_T_CHAR: + case PSI_T_SINT8: + case PSI_T_UINT8: + if (!func->var->pointer_level) { + char chr = ret_val->lval; + RETVAL_STRINGL(&chr, 1); + } else { + ret_val = deref_impl_val(1, ret_val, func); + if (ret_val->ptr) { + RETVAL_STRING(ret_val->ptr); + } else { + RETVAL_EMPTY_STRING(); + } + } + break; + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + RETVAL_DOUBLE(deref_impl_val(0, ret_val, func)->dval); + convert_to_string(return_value); + break; + default: + RETVAL_LONG(deref_impl_val(0, ret_val, func)->lval); + convert_to_string(return_value); + break; + } +} + +ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl) +{ + impl_arg *iarg; + + if (!impl->func->args->count) { + return zend_parse_parameters_none(); + } + + ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->count) + nextarg: + iarg = impl->func->args->args[_i]; + if (iarg->def) { + Z_PARAM_OPTIONAL; + } + if (PSI_T_BOOL == iarg->type->type) { + if (iarg->def) { + iarg->val.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0; + } + Z_PARAM_BOOL(iarg->val.bval); + } else if (PSI_T_INT == iarg->type->type) { + if (iarg->def) { + iarg->val.lval = zend_atol(iarg->def->text, strlen(iarg->def->text)); + } + Z_PARAM_LONG(iarg->val.lval); + } else if (PSI_T_FLOAT == iarg->type->type) { + if (iarg->def) { + iarg->val.dval = zend_strtod(iarg->def->text, NULL); + } + Z_PARAM_DOUBLE(iarg->val.dval); + } else if (PSI_T_STRING == iarg->type->type) { + struct {char *val; size_t len;} str; + if (iarg->def) { + /* FIXME */ + str.len = strlen(iarg->def->text) - 2; + str.val = &iarg->def->text[1]; + } + Z_PARAM_STR_EX(iarg->val.str, 1, 0); + if (iarg->val.str) { + zend_string_addref(iarg->val.str); + } else if (iarg->def) { + iarg->val.str = zend_string_init(str.val, str.len, 0); + } + } else { + error_code = ZPP_ERROR_FAILURE; + break; + } + iarg->_zv = _arg; + if (_i < _max_num_args) { + goto nextarg; + } + ZEND_PARSE_PARAMETERS_END_EX(return FAILURE); + + return SUCCESS; +} + +impl_val *psi_do_let(decl_arg *darg) +{ + impl_val *arg_val = &darg->let->out; + impl_arg *iarg = darg->let->arg; + + if (!iarg) { + /* let foo = NULL */ + memset(arg_val, 0, sizeof(*arg_val)); + return arg_val; + } + switch (darg->let->val->func->type) { + case PSI_T_BOOLVAL: + if (iarg->type->type == PSI_T_BOOL) { + arg_val->cval = iarg->val.cval; + } else { + arg_val->cval = zend_is_true(iarg->_zv); + } + break; + case PSI_T_INTVAL: + if (iarg->type->type == PSI_T_INT) { + arg_val->lval = iarg->val.lval; + } else { + arg_val->lval = zval_get_long(iarg->_zv); + } + break; + case PSI_T_STRVAL: + if (iarg->type->type == PSI_T_STRING) { + arg_val->ptr = estrdup(iarg->val.str->val); + darg->let->mem = arg_val->ptr; + zend_string_release(iarg->val.str); + } else { + zend_string *zs = zval_get_string(iarg->_zv); + arg_val->ptr = estrdup(zs->val); + darg->let->mem = arg_val->ptr; + zend_string_release(zs); + } + break; + case PSI_T_STRLEN: + if (iarg->type->type == PSI_T_STRING) { + arg_val->lval = iarg->val.str->len; + zend_string_release(iarg->val.str); + } else { + zend_string *zs = zval_get_string(iarg->_zv); + arg_val->lval = zs->len; + zend_string_release(zs); + } + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + + return arg_val; +} + +void psi_do_set(zval *return_value, set_func *func, decl_vars *vars) +{ + impl_val *val = (impl_val *) &vars->vars[0]->arg->let->ptr; + + ZVAL_DEREF(return_value); + zval_dtor(return_value); + + switch (func->type) { + case PSI_T_TO_STRING: + psi_to_string(val, vars->vars[0]->arg, return_value); + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } +} + +void psi_do_return(impl *impl, impl_val *ret_val, zval *return_value) +{ + switch (impl->stmts->ret.list[0]->func->type) { + case PSI_T_TO_STRING: + psi_to_string(ret_val, impl->decl->func, return_value); + break; + case PSI_T_TO_INT: + psi_to_int(ret_val, impl->decl->func, return_value); + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } +} + +void psi_do_free(free_stmt *fre) +{ + size_t i; + + for (i = 0; i < fre->vars->count; ++i) { + decl_var *dvar = fre->vars->vars[i]; + + if (dvar->arg && dvar->arg->let->out.ptr) { + free(dvar->arg->let->out.ptr); + dvar->arg->let->out.ptr = NULL; + } + } +} + +void psi_do_clean(impl *impl) +{ + size_t i; + + for (i = 0; i < impl->decl->args->count; ++i) { + decl_arg *darg = impl->decl->args->args[i]; + + if (darg->let && darg->let->mem) { + efree(darg->let->mem); + darg->let->mem = NULL; + } + } +} + PHP_MINIT_FUNCTION(psi) { REGISTER_INI_ENTRIES(); diff --git a/src/parser.h b/src/parser.h index d7393d4..ce74067 100644 --- a/src/parser.h +++ b/src/parser.h @@ -89,16 +89,6 @@ static void free_decl_typedefs(decl_typedefs *defs) { free(defs); } -typedef union impl_val { - char cval; - short sval; - int ival; - double dval; - zend_long lval; - zend_string *str; - void *ptr; -} impl_val; - typedef struct decl_var { char *name; unsigned pointer_level; @@ -256,6 +246,26 @@ static inline void free_decls(decls *decls) { free(decls); } +typedef union impl_val { + unsigned char bval; + char cval; + short sval; + int ival; + double dval; + zend_long lval; + zend_string *str; + void *ptr; +} impl_val; + +static inline impl_val *deref_impl_val(unsigned level, impl_val *ret_val, decl_arg *darg) { + unsigned i; + + for (i = level; i < darg->var->pointer_level && ret_val->ptr; ++i) { + ret_val = *(void **)ret_val; + } + return ret_val; +} + typedef struct impl_type { char *name; token_t type; @@ -616,6 +626,7 @@ static inline impl_stmts *add_impl_stmt(impl_stmts *stmts, impl_stmt *stmt) { stmts->fre.list = add_impl_stmt_ex(stmts->fre.list, ++stmts->fre.count, stmt->s.fre); break; } + free(stmt); return stmts; } diff --git a/src/parser_proc.y b/src/parser_proc.y index f7bec63..85fac69 100644 --- a/src/parser_proc.y +++ b/src/parser_proc.y @@ -11,6 +11,7 @@ %token_prefix PSI_T_ %token_type {PSI_Token *} %token_destructor {free($$);} +%default_destructor {(void)P;} %extra_argument {PSI_Parser *P} /* TOKEN is defined inside syntax_error */ %syntax_error { @@ -83,6 +84,7 @@ decl(decl) ::= decl_abi(abi) decl_arg(func) LPAREN decl_args(args) RPAREN EOS. { %type decl_abi {decl_abi*} decl_abi(abi) ::= NAME(T). { abi = init_decl_abi(T->text); + free(T); } %type decl_var {decl_var*} @@ -202,18 +204,23 @@ impl_func(func) ::= FUNCTION REFERENCE NSNAME(NAME) impl_args(args) COLON impl_t %type impl_def_val {impl_def_val*} impl_def_val(def) ::= NULL(T). { def = init_impl_def_val(T); + free(T); } impl_def_val(def) ::= NUMBER(T). { def = init_impl_def_val(T); + free(T); } impl_def_val(def) ::= TRUE(T). { def = init_impl_def_val(T); + free(T); } impl_def_val(def) ::= FALSE(T). { def = init_impl_def_val(T); + free(T); } impl_def_val(def) ::= QUOTED_STRING(T). { def = init_impl_def_val(T); + free(T); } %type impl_var {impl_var*} -- 2.30.2