diff options
author | David Walker <dwalker@n.io> | 2017-10-06 17:30:58 -0600 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2017-12-09 13:39:52 +0100 |
commit | 6d4de4cf0582cf33848826ab78aae58077dc2dea (patch) | |
tree | e12b5a758af578d0ac96100ca2089e583391f099 /ext | |
parent | 261ddb760a04fcdf8d3dd12a4745bc1f6c3f9424 (diff) | |
download | php-git-6d4de4cf0582cf33848826ab78aae58077dc2dea.tar.gz |
Implement list() reference assignments
Support list() reference assignments of the form:
list(&$a, list(&$b, $c)) = $d;
RFC: https://wiki.php.net/rfc/list_reference_assignment
Diffstat (limited to 'ext')
-rw-r--r-- | ext/opcache/Optimizer/block_pass.c | 3 | ||||
-rw-r--r-- | ext/opcache/Optimizer/sccp.c | 7 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_dfg.c | 1 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_inference.c | 23 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer.c | 13 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_ssa.c | 3 |
6 files changed, 34 insertions, 16 deletions
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index fcd20c86fe..78b5176dd7 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -410,7 +410,8 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array } #endif - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: + case ZEND_FETCH_LIST_W: if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { /* LIST variable will be deleted later by FREE */ Tsource[VAR_NUM(opline->op1.var)] = NULL; diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c index b778286b7c..aa1550f5fb 100644 --- a/ext/opcache/Optimizer/sccp.c +++ b/ext/opcache/Optimizer/sccp.c @@ -220,6 +220,7 @@ static zend_bool can_replace_op1( case ZEND_FETCH_OBJ_RW: case ZEND_FETCH_OBJ_UNSET: case ZEND_FETCH_OBJ_FUNC_ARG: + case ZEND_FETCH_LIST_W: case ZEND_UNSET_DIM: case ZEND_UNSET_OBJ: case ZEND_SEND_REF: @@ -286,7 +287,7 @@ static zend_bool try_replace_op1( } else { // TODO: check the following special cases ??? switch (opline->opcode) { - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: case ZEND_CASE: case ZEND_SWITCH_STRING: case ZEND_SWITCH_LONG: @@ -1521,11 +1522,11 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o break; case ZEND_FETCH_DIM_R: case ZEND_FETCH_DIM_IS: - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: SKIP_IF_TOP(op1); SKIP_IF_TOP(op2); - if (ct_eval_fetch_dim(&zv, op1, op2, (opline->opcode != ZEND_FETCH_LIST)) == SUCCESS) { + if (ct_eval_fetch_dim(&zv, op1, op2, (opline->opcode != ZEND_FETCH_LIST_R)) == SUCCESS) { SET_RESULT(result, &zv); zval_ptr_dtor_nogc(&zv); break; diff --git a/ext/opcache/Optimizer/zend_dfg.c b/ext/opcache/Optimizer/zend_dfg.c index 49be85c6b8..2ac060ba7e 100644 --- a/ext/opcache/Optimizer/zend_dfg.c +++ b/ext/opcache/Optimizer/zend_dfg.c @@ -127,6 +127,7 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg case ZEND_FETCH_OBJ_RW: case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_FETCH_OBJ_UNSET: + case ZEND_FETCH_LIST_W: case ZEND_VERIFY_RETURN_TYPE: case ZEND_PRE_INC_OBJ: case ZEND_PRE_DEC_OBJ: diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index d096e1aa23..02ac1e14d8 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -2994,12 +2994,14 @@ static int zend_update_type_info(const zend_op_array *op_array, case ZEND_FETCH_DIM_W: case ZEND_FETCH_DIM_UNSET: case ZEND_FETCH_DIM_FUNC_ARG: - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: + case ZEND_FETCH_LIST_W: if (ssa_ops[i].op1_def >= 0) { tmp = t1 & ~(MAY_BE_RC1|MAY_BE_RCN); if (opline->opcode == ZEND_FETCH_DIM_W || opline->opcode == ZEND_FETCH_DIM_RW || - opline->opcode == ZEND_FETCH_DIM_FUNC_ARG) { + opline->opcode == ZEND_FETCH_DIM_FUNC_ARG || + opline->opcode == ZEND_FETCH_LIST_W) { if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) { if (opline->opcode != ZEND_FETCH_DIM_FUNC_ARG) { tmp &= ~(MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE); @@ -3046,6 +3048,7 @@ static int zend_update_type_info(const zend_op_array *op_array, case ZEND_FETCH_DIM_W: case ZEND_FETCH_DIM_RW: case ZEND_FETCH_DIM_FUNC_ARG: + case ZEND_FETCH_LIST_W: case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_SUB: case ZEND_ASSIGN_MUL: @@ -3116,13 +3119,14 @@ static int zend_update_type_info(const zend_op_array *op_array, } /* FETCH_LIST on a string behaves like FETCH_R on null */ tmp = zend_array_element_type( - opline->opcode != ZEND_FETCH_LIST ? t1 : ((t1 & ~MAY_BE_STRING) | MAY_BE_NULL), + opline->opcode != ZEND_FETCH_LIST_R ? t1 : ((t1 & ~MAY_BE_STRING) | MAY_BE_NULL), opline->opcode != ZEND_FETCH_DIM_R && opline->opcode != ZEND_FETCH_DIM_IS - && opline->opcode != ZEND_FETCH_LIST, + && opline->opcode != ZEND_FETCH_LIST_R, opline->op2_type == IS_UNUSED); if (opline->opcode == ZEND_FETCH_DIM_W || opline->opcode == ZEND_FETCH_DIM_RW || - opline->opcode == ZEND_FETCH_DIM_FUNC_ARG) { + opline->opcode == ZEND_FETCH_DIM_FUNC_ARG || + opline->opcode == ZEND_FETCH_LIST_W) { if (t1 & (MAY_BE_ERROR|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE|MAY_BE_OBJECT)) { tmp |= MAY_BE_ERROR; } else if (opline->op2_type == IS_UNUSED) { @@ -3258,6 +3262,13 @@ static int zend_update_type_info(const zend_op_array *op_array, } } break; + case ZEND_MAKE_REF: + 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; + UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + if (ssa_ops[i].op1_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + } + break; case ZEND_CATCH: case ZEND_INCLUDE_OR_EVAL: /* Forbidden opcodes */ @@ -4007,7 +4018,7 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa case ZEND_CASE: case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: case ZEND_QM_ASSIGN: case ZEND_SEND_VAL: case ZEND_SEND_VAL_EX: diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 1e5b4a2a73..f63c2c0383 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -269,6 +269,7 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array, case ZEND_FETCH_DIM_RW: case ZEND_FETCH_DIM_FUNC_ARG: case ZEND_FETCH_DIM_UNSET: + case ZEND_FETCH_LIST_W: case ZEND_ASSIGN_DIM: case ZEND_RETURN_BY_REF: return 0; @@ -307,7 +308,7 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array, * zend_optimizer_replace_by_const() supports this. */ return 0; case ZEND_CASE: - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: return 0; case ZEND_CONCAT: case ZEND_FAST_CONCAT: @@ -450,7 +451,8 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array, case ZEND_FETCH_DIM_IS: case ZEND_FETCH_DIM_FUNC_ARG: case ZEND_FETCH_DIM_UNSET: - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: + case ZEND_FETCH_LIST_W: if (Z_TYPE_P(val) == IS_STRING) { zend_ulong index; if (ZEND_HANDLE_NUMERIC(Z_STR_P(val), index)) { @@ -571,6 +573,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, case ZEND_FETCH_DIM_RW: case ZEND_FETCH_DIM_FUNC_ARG: case ZEND_FETCH_DIM_UNSET: + case ZEND_FETCH_LIST_W: case ZEND_ASSIGN_DIM: case ZEND_SEPARATE: case ZEND_RETURN_BY_REF: @@ -593,15 +596,15 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, break; /* In most cases IS_TMP_VAR operand may be used only once. * The operands are usually destroyed by the opcode handler. - * ZEND_CASE and ZEND_FETCH_LIST are exceptions, they keeps operand + * ZEND_CASE and ZEND_FETCH_LIST_R are exceptions, they keeps operand * unchanged, and allows its reuse. these instructions * usually terminated by ZEND_FREE that finally kills the value. */ - case ZEND_FETCH_LIST: { + case ZEND_FETCH_LIST_R: { zend_op *m = opline; do { - if (m->opcode == ZEND_FETCH_LIST && + if (m->opcode == ZEND_FETCH_LIST_R && m->op1_type == type && m->op1.var == var) { zval v; diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index 6dfb13886e..2bb4f6452f 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -683,7 +683,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, case ZEND_SEND_REF: case ZEND_SEND_UNPACK: case ZEND_FE_RESET_RW: -//TODO: ??? + case ZEND_MAKE_REF: if (opline->op1_type == IS_CV) { ssa_ops[k].op1_def = ssa_vars_count; var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count; @@ -737,6 +737,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, case ZEND_FETCH_OBJ_RW: case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_FETCH_OBJ_UNSET: + case ZEND_FETCH_LIST_W: if (opline->op1_type == IS_CV) { ssa_ops[k].op1_def = ssa_vars_count; var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count; |