From: Nikita Popov Date: Tue, 3 Sep 2019 08:32:47 +0000 (+0200) Subject: Support computing func info from ret arg info for internal funcs X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=597a5da0274614b726ac309573760cbde8709e03;p=php Support computing func info from ret arg info for internal funcs --- diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c index 9a34e855e3..936b46c964 100644 --- a/ext/opcache/Optimizer/zend_func_info.c +++ b/ext/opcache/Optimizer/zend_func_info.c @@ -1473,11 +1473,11 @@ uint32_t zend_get_func_info(const zend_call_info *call_info, const zend_ssa *ssa if (callee_func->type == ZEND_INTERNAL_FUNCTION) { zval *zv; - func_info_t *info; + zend_string *lcname = Z_STR_P(CRT_CONSTANT_EX(call_info->caller_op_array, call_info->caller_init_opline, call_info->caller_init_opline->op2, ssa->rt_constants)); - zv = zend_hash_find_ex(&func_info, Z_STR_P(CRT_CONSTANT_EX(call_info->caller_op_array, call_info->caller_init_opline, call_info->caller_init_opline->op2, ssa->rt_constants)), 1); + zv = zend_hash_find_ex(&func_info, lcname, 1); if (zv) { - info = Z_PTR_P(zv); + func_info_t *info = Z_PTR_P(zv); if (UNEXPECTED(zend_optimizer_is_disabled_func(info->name, info->name_len))) { ret = MAY_BE_NULL; } else if (info->info_func) { @@ -1485,10 +1485,21 @@ uint32_t zend_get_func_info(const zend_call_info *call_info, const zend_ssa *ssa } else { ret = info->info; } -#if 0 + return ret; + } + + if (callee_func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { + zend_class_entry *ce; // TODO: Use the CE. + ret = zend_fetch_arg_info_type(NULL, callee_func->common.arg_info - 1, &ce); } else { +#if 0 fprintf(stderr, "Unknown internal function '%s'\n", func->common.function_name); #endif + ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF + | MAY_BE_RC1 | MAY_BE_RCN; + } + if (callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) { + ret |= MAY_BE_REF; } } else { // FIXME: the order of functions matters!!! @@ -1496,15 +1507,14 @@ uint32_t zend_get_func_info(const zend_call_info *call_info, const zend_ssa *ssa if (info) { ret = info->return_info.type; } - } - if (!ret) { - ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; - if (callee_func->common.fn_flags & ZEND_ACC_GENERATOR) { - ret = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_OBJECT; - } else if (callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) { - ret |= MAY_BE_REF; - } else { - ret |= MAY_BE_RC1 | MAY_BE_RCN; + if (!ret) { + ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF + | MAY_BE_RC1 | MAY_BE_RCN; + /* For generators RETURN_REFERENCE refers to the yielded values. */ + if ((callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) + && !(callee_func->common.fn_flags & ZEND_ACC_GENERATOR)) { + ret |= MAY_BE_REF; + } } } return ret; diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 8e2c27890e..da4f0846ef 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -2250,7 +2250,7 @@ static uint32_t zend_convert_type_code_to_may_be(zend_uchar type_code) { } } -static uint32_t zend_fetch_arg_info(const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce) +uint32_t zend_fetch_arg_info_type(const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce) { uint32_t tmp = 0; @@ -2269,6 +2269,9 @@ static uint32_t zend_fetch_arg_info(const zend_script *script, zend_arg_info *ar if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) { tmp |= MAY_BE_NULL; } + if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { + tmp |= MAY_BE_RC1 | MAY_BE_RCN; + } return tmp; } @@ -3100,7 +3103,7 @@ static int zend_update_type_info(const zend_op_array *op_array, ce = NULL; if (arg_info) { - tmp = zend_fetch_arg_info(script, arg_info, &ce); + tmp = zend_fetch_arg_info_type(script, arg_info, &ce); if (opline->opcode == ZEND_RECV_INIT && Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)) == IS_CONSTANT_AST) { /* The constant may resolve to NULL */ @@ -3108,8 +3111,6 @@ static int zend_update_type_info(const zend_op_array *op_array, } if (arg_info->pass_by_reference) { tmp |= MAY_BE_REF; - } else if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - tmp |= MAY_BE_RC1|MAY_BE_RCN; } } else { tmp = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; @@ -3613,11 +3614,7 @@ static int zend_update_type_info(const zend_op_array *op_array, ce = NULL; } else { zend_arg_info *ret_info = op_array->arg_info - 1; - - tmp = zend_fetch_arg_info(script, ret_info, &ce); - if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - tmp |= MAY_BE_RC1 | MAY_BE_RCN; - } + tmp = zend_fetch_arg_info_type(script, ret_info, &ce); } if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) { UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); @@ -4044,11 +4041,9 @@ void zend_init_func_return_info(const zend_op_array *op_array, zend_arg_info *ret_info = op_array->arg_info - 1; zend_ssa_range tmp_range = {0, 0, 0, 0}; - ret->type = zend_fetch_arg_info(script, ret_info, &ret->ce); + ret->type = zend_fetch_arg_info_type(script, ret_info, &ret->ce); if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) { ret->type |= MAY_BE_REF; - } else if (ret->type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - ret->type |= MAY_BE_RC1|MAY_BE_RCN; } ret->is_instanceof = (ret->ce) ? 1 : 0; ret->range = tmp_range; diff --git a/ext/opcache/Optimizer/zend_inference.h b/ext/opcache/Optimizer/zend_inference.h index ec98fcbef9..03cbb5e82b 100644 --- a/ext/opcache/Optimizer/zend_inference.h +++ b/ext/opcache/Optimizer/zend_inference.h @@ -263,6 +263,8 @@ void zend_inference_check_recursive_dependencies(zend_op_array *op_array); int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist, zend_long optimization_level); +uint32_t zend_fetch_arg_info_type( + const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce); void zend_init_func_return_info(const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret);