X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=blobdiff_plain;f=src%2Flibjit.c;h=7b0a49a5cadd6748edd886ba5345570c9d292ddf;hp=5cc8525931c4f63999b3fe7640d80b4a14562cda;hb=c0999079ea85fecba8ab5eec386541fc1ce733b7;hpb=762750b4a3f4e0471993849c4bd12965f6b62356 diff --git a/src/libjit.c b/src/libjit.c index 5cc8525..7b0a49a 100644 --- a/src/libjit.c +++ b/src/libjit.c @@ -1,64 +1,47 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include "php.h" -#include "libjit.h" -#include "parser_proc.h" -#include "parser.h" -#include +#ifdef HAVE_LIBJIT -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; -} +#include "php_psi.h" +#include "libjit.h" -static inline size_t impl_num_min_args(impl *impl) { - size_t i, n = impl->func->args->count; +#include - for (i = 0; i < impl->func->args->count; ++i) { - if (impl->func->args->args[i]->def) { - --n; - } - } - return n; -} +static void psi_jit_handler(jit_type_t _sig, void *result, void **_args, void *_data); +static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg); static inline jit_abi_t psi_jit_abi(const char *convention) { return jit_abi_cdecl; } -static inline jit_type_t psi_jit_type(token_t t) { +static inline jit_type_t psi_jit_token_type(token_t t) { switch (t) { default: ZEND_ASSERT(0); /* no break */ case PSI_T_VOID: return jit_type_void; - case PSI_T_SINT8: + case PSI_T_INT8: return jit_type_sbyte; case PSI_T_UINT8: return jit_type_ubyte; - case PSI_T_SINT16: + case PSI_T_INT16: return jit_type_short; case PSI_T_UINT16: return jit_type_ushort; - case PSI_T_SINT32: + case PSI_T_INT32: return jit_type_int; case PSI_T_UINT32: return jit_type_uint; - case PSI_T_SINT64: + case PSI_T_INT64: return jit_type_long; case PSI_T_UINT64: return jit_type_ulong; case PSI_T_BOOL: return jit_type_sys_bool; - case PSI_T_CHAR: - return jit_type_sys_char; - case PSI_T_SHORT: - return jit_type_sys_short; case PSI_T_INT: return jit_type_sys_int; case PSI_T_LONG: @@ -67,382 +50,310 @@ static inline jit_type_t psi_jit_type(token_t t) { return jit_type_sys_float; case PSI_T_DOUBLE: return jit_type_sys_double; +#ifdef HAVE_LONG_DOUBLE + case PSI_T_LONG_DOUBLE: + return jit_type_sys_long_double; +#endif + case PSI_T_POINTER: + return jit_type_void_ptr; } } -static inline jit_type_t psi_jit_decl_type(decl_type *type) { - return psi_jit_type(real_decl_type(type)->type); -} -static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) { - if (darg->var->pointer_level) { +static inline jit_type_t psi_jit_impl_type(token_t impl_type) { + switch (impl_type) { + case PSI_T_BOOL: + return jit_type_sbyte; + case PSI_T_INT: + return jit_type_long; + case PSI_T_STRING: return jit_type_void_ptr; - } else { - return psi_jit_decl_type(darg->type); + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + return jit_type_sys_double; + EMPTY_SWITCH_DEFAULT_CASE(); } + return NULL; } +static void psi_jit_struct_type_dtor(void *type) { + jit_type_t strct = type; -typedef struct PSI_ClosureData { - void *context; - impl *impl; - jit_type_t signature; - jit_type_t params[1]; -} PSI_ClosureData; - -static inline PSI_ClosureData *PSI_ClosureDataAlloc(void *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)); - - data->context = context; - data->impl = 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; + jit_type_free(strct); } +static size_t psi_jit_struct_type_pad(jit_type_t **els, size_t padding) { + size_t i; -static inline impl_val *deref(unsigned level, impl_val *ret_val, decl_arg *darg) { - unsigned i; - - for (i = level; i < darg->var->pointer_level; ++i && ret_val->ptr) { - ret_val = *(void **)ret_val; + for (i = 0; i < padding; ++i) { + *els++ = jit_type_copy(jit_type_sys_char); } - 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 padding; } -static ZEND_RESULT_CODE handle_args(zend_execute_data *execute_data, impl *impl) { - impl_arg *iarg; +static unsigned psi_jit_struct_type_elements(decl_struct *strct, jit_type_t **fields) { + size_t i, j, argc = strct->args->count, nels = 0, offset = 0, maxalign; + *fields = calloc(argc + 1, sizeof(*fields)); - if (!impl->func->args->count) { - return zend_parse_parameters_none(); - } + for (i = 0; i < strct->args->count; ++i) { + decl_arg *darg = strct->args->args[i]; + jit_type_t type = jit_type_copy(psi_jit_decl_arg_type(darg)); + size_t padding, alignment; + + ZEND_ASSERT(jit_type_get_size(type) == darg->layout->len); - 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 ((alignment = jit_type_get_alignment(type)) > maxalign) { + maxalign = alignment; } - 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); + + if ((padding = psi_offset_padding(darg->layout->pos - offset, alignment))) { + if (nels + padding > argc) { + argc += padding; + *fields = realloc(*fields, (argc + 1) * sizeof(*fields)); } - } else { - error_code = ZPP_ERROR_FAILURE; - break; + psi_jit_struct_type_pad(&(*fields)[nels], padding); + nels += padding; + offset += padding; } - iarg->_zv = _arg; - if (_i < _max_num_args) { - goto nextarg; - } - ZEND_PARSE_PARAMETERS_END_EX(return FAILURE); + ZEND_ASSERT(offset == darg->layout->pos); - return SUCCESS; -} - -static impl_val *handle_let(decl_arg *darg, impl_arg *iarg) { - impl_val *arg_val = &darg->let->out; - - 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(); + offset = (offset + darg->layout->len + alignment - 1) & ~(alignment - 1); + (*fields)[nels++] = type; } - return arg_val; -} + /* apply struct alignment padding */ + offset = (offset + maxalign - 1) & ~(maxalign - 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(); + ZEND_ASSERT(offset <= strct->size); + if (offset < strct->size) { + nels += psi_jit_struct_type_pad(&(*fields)[nels], strct->size - offset); } -} - -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); - - switch (func->type) { - case PSI_T_TO_STRING: - to_string(val, vars->vars[0]->arg, return_value); - break; - EMPTY_SWITCH_DEFAULT_CASE(); - } + return nels; } +static inline jit_type_t psi_jit_decl_type(decl_type *type) { + decl_type *real = real_decl_type(type); -static void handle_free(free_stmt *fre) { - size_t i; + if (real->type == PSI_T_STRUCT) { + if (!real->strct->engine.type) { + unsigned count; + jit_type_t strct, *fields = NULL; - for (i = 0; i < fre->vars->count; ++i) { - decl_var *dvar = fre->vars->vars[i]; + count = psi_jit_struct_type_elements(real->strct, &fields); + strct = jit_type_create_struct(fields, count, 0); - if (dvar->arg && dvar->arg->let->out.ptr) { - free(dvar->arg->let->out.ptr); - dvar->arg->let->out.ptr = NULL; + real->strct->engine.type = strct; + real->strct->engine.dtor = psi_jit_struct_type_dtor; } + + return real->strct->engine.type; } + return psi_jit_token_type(real->type); } - -static void handler(jit_type_t _sig, void *result, void **_args, void *_data) -{ - PSI_ClosureData *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)) { - return; +static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) { + if (darg->var->pointer_level) { + return jit_type_void_ptr; + } else { + return psi_jit_decl_type(darg->type); } +} - if (data->impl->decl->args->count) { - arg_ptr = malloc(data->impl->decl->args->count * sizeof(*arg_ptr)); - arg_prm = malloc(data->impl->decl->args->count * sizeof(*arg_prm)); +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_LibjitCall { + void *closure; + jit_type_t signature; + void *params[1]; /* [type1, type2, NULL, arg1, arg2] ... */ +} PSI_LibjitCall; - 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; +typedef struct PSI_LibjitData { + PSI_LibjitContext *context; + impl *impl; + zend_internal_arg_info *arginfo; +} PSI_LibjitData; - arg_ptr[i] = handle_let(darg, iarg); - arg_prm[i] = darg->let->val->is_reference ? &arg_ptr[i] : arg_ptr[i]; +static inline PSI_LibjitCall *PSI_LibjitCallAlloc(PSI_Context *C, decl *decl) { + size_t i, c = decl->args ? decl->args->count : 0; + PSI_LibjitCall *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *)); - darg->let->ptr = arg_ptr[i]; - } + for (i = 0; i < c; ++i) { + call->params[i] = psi_jit_decl_arg_type(decl->args->args[i]); } + call->params[c] = NULL; + + decl->call.info = call; + decl->call.rval = &decl->func->ptr; + decl->call.argc = c; + decl->call.args = (void **) &call->params[c+1]; + + call->signature = jit_type_create_signature( + psi_jit_abi(decl->abi->convention), + psi_jit_decl_arg_type(decl->func), + (jit_type_t *) call->params, c, 1); + return call; +} - jit_apply(data->signature, data->impl->decl->dlptr, arg_prm, data->impl->decl->args->count, &ret_val); +static inline void PSI_LibjitCallInitClosure(PSI_Context *C, PSI_LibjitCall *call, impl *impl) { + PSI_LibjitContext *context = C->context; + call->closure = jit_closure_create(context->jit, context->signature, + &psi_jit_handler, impl); +} - handle_rval(data->impl, &ret_val, *(zval **)_args[1]); +static inline void PSI_LibjitCallFree(PSI_LibjitCall *call) { + jit_type_free(call->signature); + free(call); +} - for (i = 0; i < data->impl->stmts->set.count; ++i) { - set_stmt *set = data->impl->stmts->set.list[i]; +static inline PSI_LibjitContext *PSI_LibjitContextInit(PSI_LibjitContext *L) { + jit_type_t params[] = { + jit_type_void_ptr, + jit_type_void_ptr + }; - handle_set(set->arg->_zv, set->val->func, set->val->vars); + if (!L) { + L = malloc(sizeof(*L)); } + memset(L, 0, sizeof(*L)); - 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]; + L->jit = jit_context_create(); + L->signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void, + params, 2, 1); - if (darg->let && darg->let->mem) { - efree(darg->let->mem); - darg->let->mem = NULL; - } - } - free(arg_ptr); - free(arg_prm); - } - - for (i = 0; i < data->impl->stmts->fre.count; ++i) { - free_stmt *fre = data->impl->stmts->fre.list[i]; + return L; +} - handle_free(fre); - } +static inline void PSI_LibjitContextDtor(PSI_LibjitContext *L) { + jit_type_free(L->signature); + jit_context_destroy(L->jit); } -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; +static inline void PSI_LibjitContextFree(PSI_LibjitContext **L) { + if (*L) { + PSI_LibjitContextDtor(*L); + free(*L); + *L = NULL; } } -static inline zend_internal_arg_info *fill_arginfo(impl *impl) { - size_t i; - zend_internal_arg_info *aip; - zend_internal_function_info *fi; +static void psi_jit_handler(jit_type_t _sig, void *result, void **_args, void *_data) +{ + psi_call(*(zend_execute_data **)_args[0], *(zval **)_args[1], _data); +} - aip = calloc(impl->func->args->count + 1, sizeof(*aip)); +static void psi_jit_init(PSI_Context *C) +{ + C->context = PSI_LibjitContextInit(NULL); +} - 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); +static void psi_jit_dtor(PSI_Context *C) +{ + if (C->decls) { + size_t i; - 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]; + for (i = 0; i < C->decls->count; ++i) { + decl *decl = C->decls->list[i]; - 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; + PSI_LibjitCallFree(decl->call.info); } } - - return aip; + PSI_LibjitContextFree((void *) &C->context); } -static zend_function_entry *compile(PSI_Context *C, PSI_Data *D) +static zend_function_entry *psi_jit_compile(PSI_Context *C) { 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)); + zend_function_entry *zfe; + PSI_LibjitContext *ctx = C->context; + + if (!C->impls) { + return NULL; + } - jit_context_build_start(C->context); + zfe = calloc(C->impls->count + 1, sizeof(*zfe)); + jit_context_build_start(ctx->jit); - for (i = 0; i < D->impls->count; ++i) { + for (i = 0; i < C->impls->count; ++i) { zend_function_entry *zf = &zfe[j]; - PSI_ClosureData *data; + PSI_LibjitCall *call; + impl *impl = C->impls->list[i]; - if (!D->impls->list[i]->decl) { + if (!impl->decl) { continue; } - data = PSI_ClosureDataAlloc(C, D->impls->list[i]); - signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void, params, 2, 1); - 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]); + call = PSI_LibjitCallAlloc(C, impl->decl); + PSI_LibjitCallInitClosure(C, call, impl); + + zf->fname = impl->func->name + (impl->func->name[0] == '\\'); + zf->num_args = impl->func->args->count; + zf->handler = call->closure; + zf->arg_info = psi_internal_arginfo(impl); ++j; } - jit_context_build_end(C->context); + for (i = 0; i < C->decls->count; ++i) { + decl *decl = C->decls->list[i]; + + if (decl->impl) { + continue; + } + + PSI_LibjitCallAlloc(C, decl); + } + + jit_context_build_end(ctx->jit); return zfe; } +static void psi_jit_call(PSI_Context *C, decl_callinfo *decl_call, impl_vararg *va) { + PSI_LibjitCall *call = decl_call->info; + + if (va) { + jit_type_t 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_jit_impl_type(va->types[i]); + params[nfixedargs + i + ntotalargs + 1] = &va->values[i]; + } + + signature = jit_type_create_signature( + jit_type_get_abi(call->signature), + jit_type_get_return(call->signature), + (jit_type_t *) params, ntotalargs, 1); + ZEND_ASSERT(signature); + + jit_apply(signature, decl_call->sym, ¶ms[ntotalargs + 1], + nfixedargs, *decl_call->rval); + jit_type_free(signature); + free(params); + } else { + jit_apply(call->signature, decl_call->sym, decl_call->args, + decl_call->argc, *decl_call->rval); + } +} + static PSI_ContextOps ops = { - init, - dtor, - compile, + psi_jit_init, + psi_jit_dtor, + psi_jit_compile, + psi_jit_call, }; PSI_ContextOps *PSI_Libjit(void) { return &ops; } + +#endif /* HAVE_LIBJIT */