From ab5f8f4bafdd0231d1483667155b773dd6dfb383 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 7 Jul 2020 19:11:27 +0300 Subject: [PATCH] More accurate reference-counter inference (with support for ext/intl/tests/bug72241.phpt) --- ext/opcache/Optimizer/zend_inference.c | 18 +++++++++++------- ext/opcache/Optimizer/zend_inference.h | 2 +- ext/opcache/jit/zend_jit_x86.dasc | 15 +++++++++++---- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index d45b58d6d7..c4189975d5 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -1952,7 +1952,7 @@ static void emit_type_narrowing_warning(const zend_op_array *op_array, zend_ssa zend_error(E_WARNING, "Narrowing occurred during type inference of %s. Please file a bug report on bugs.php.net", def_op_name); } -uint32_t zend_array_element_type(uint32_t t1, int write, int insert) +uint32_t zend_array_element_type(uint32_t t1, zend_uchar op_type, int write, int insert) { uint32_t tmp = 0; @@ -1972,15 +1972,18 @@ uint32_t zend_array_element_type(uint32_t t1, int write, int insert) if (tmp & MAY_BE_ARRAY) { tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; } - if (t1 & MAY_BE_ARRAY_OF_REF) { + if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { if (!write) { /* can't be REF because of ZVAL_COPY_DEREF() usage */ - tmp |= MAY_BE_RC1 | MAY_BE_RCN; - } else { + tmp |= MAY_BE_RCN; + if ((op_type & (IS_VAR|IS_TMP_VAR)) && (t1 & MAY_BE_RC1)) { + tmp |= MAY_BE_RC1; + } + } else if (t1 & MAY_BE_ARRAY_OF_REF) { tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN; + } else { + tmp |= MAY_BE_RC1 | MAY_BE_RCN; } - } else if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - tmp |= MAY_BE_RC1 | MAY_BE_RCN; } } if (write) { @@ -2513,7 +2516,7 @@ static zend_always_inline int _zend_update_type_info( tmp |= MAY_BE_REF; } orig = t1; - t1 = zend_array_element_type(t1, 1, 0); + t1 = zend_array_element_type(t1, opline->op1_type, 1, 0); t2 = OP1_DATA_INFO(); } else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP) { prop_info = zend_fetch_static_prop_info(script, op_array, ssa, opline); @@ -3380,6 +3383,7 @@ static zend_always_inline int _zend_update_type_info( /* FETCH_LIST on a string behaves like FETCH_R on null */ tmp = zend_array_element_type( opline->opcode != ZEND_FETCH_LIST_R ? t1 : ((t1 & ~MAY_BE_STRING) | MAY_BE_NULL), + opline->op1_type, opline->result_type == IS_VAR, opline->op2_type == IS_UNUSED); if (opline->opcode == ZEND_FETCH_DIM_IS && (t1 & MAY_BE_STRING)) { diff --git a/ext/opcache/Optimizer/zend_inference.h b/ext/opcache/Optimizer/zend_inference.h index 78a9cdcbb5..98a647f43a 100644 --- a/ext/opcache/Optimizer/zend_inference.h +++ b/ext/opcache/Optimizer/zend_inference.h @@ -249,7 +249,7 @@ int zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ss int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa); int zend_ssa_inference(zend_arena **raena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level); -uint32_t zend_array_element_type(uint32_t t1, int write, int insert); +uint32_t zend_array_element_type(uint32_t t1, zend_uchar op_type, int write, int insert); int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int var, int widening, int narrowing, zend_ssa_range *tmp); void zend_inference_init_range(const zend_op_array *op_array, zend_ssa *ssa, int var, zend_bool underflow, zend_long min, zend_long max, zend_bool overflow); diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index c186a7ee8f..af368defd2 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -5558,7 +5558,7 @@ static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, const ze return 0; } } else { - uint32_t var_info = zend_array_element_type(op1_info, 0, 0); + uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0); zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0); if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_W, op1_info, op2_info, 8, 8, NULL, NULL)) { @@ -5571,6 +5571,9 @@ static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, const ze if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) { var_info |= MAY_BE_REF; } + if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { + var_info |= MAY_BE_RC1; + } | // value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE); if (!zend_jit_assign_to_variable(Dst, opline, op_array, var_addr, var_info, -1, (opline+1)->op1_type, (opline+1)->op1, op3_addr, val_info, res_addr, 0)) { return 0; @@ -5756,7 +5759,7 @@ static int zend_jit_assign_dim_op(dasm_State **Dst, const zend_op *opline, const if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) { uint32_t var_info; - uint32_t var_def_info = zend_array_element_type(op1_def_info, 1, 0); + uint32_t var_def_info = zend_array_element_type(op1_def_info, opline->op1_type, 1, 0); |6: if (opline->op2_type == IS_UNUSED) { @@ -5777,10 +5780,13 @@ static int zend_jit_assign_dim_op(dasm_State **Dst, const zend_op *opline, const |.code | mov FCARG1a, r0 } else { - var_info = zend_array_element_type(op1_info, 0, 0); + var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0); if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) { var_info |= MAY_BE_REF; } + if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { + var_info |= MAY_BE_RC1; + } if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_RW, op1_info, op2_info, 8, 8, NULL, NULL)) { return 0; @@ -11132,7 +11138,8 @@ static int zend_jit_fetch_obj(dasm_State **Dst, const zend_op *opline, const zen |9: // END if (opline->op1_type != IS_UNUSED && !use_this && !op1_indirect) { if (opline->op1_type == IS_VAR - && opline->opcode == ZEND_FETCH_OBJ_W) { + && opline->opcode == ZEND_FETCH_OBJ_W + && (op1_info & MAY_BE_RC1)) { zend_jit_addr orig_op1_addr = OP1_ADDR(); | IF_NOT_ZVAL_REFCOUNTED orig_op1_addr, >1 -- 2.40.0