summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorDavid Walker <dwalker@n.io>2017-10-06 17:30:58 -0600
committerNikita Popov <nikita.ppv@gmail.com>2017-12-09 13:39:52 +0100
commit6d4de4cf0582cf33848826ab78aae58077dc2dea (patch)
treee12b5a758af578d0ac96100ca2089e583391f099 /ext
parent261ddb760a04fcdf8d3dd12a4745bc1f6c3f9424 (diff)
downloadphp-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.c3
-rw-r--r--ext/opcache/Optimizer/sccp.c7
-rw-r--r--ext/opcache/Optimizer/zend_dfg.c1
-rw-r--r--ext/opcache/Optimizer/zend_inference.c23
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c13
-rw-r--r--ext/opcache/Optimizer/zend_ssa.c3
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;