summaryrefslogtreecommitdiff
path: root/ext/opcache/Optimizer
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-11-17 10:18:37 +0100
committerNikita Popov <nikita.ppv@gmail.com>2020-11-17 10:19:57 +0100
commitdf7417d1275c53d9b38d5c3ad5d9beb263a21e08 (patch)
tree402cc77bd9597b54db07906a0703e847bc005843 /ext/opcache/Optimizer
parent78773890f6b0d82b29e0b869f3f3b22174cea217 (diff)
downloadphp-git-df7417d1275c53d9b38d5c3ad5d9beb263a21e08.tar.gz
Fix incorrectly optimized out live range
For x ? y : z style structures, the live range starts at z, but may also hold the value of y. Make sure that the refcounting check takes this into account, by checking the type of a potential phi user.
Diffstat (limited to 'ext/opcache/Optimizer')
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index 0349d0ffbe..7871fa3c8e 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -1312,11 +1312,21 @@ static void zend_adjust_fcall_stack_size_graph(zend_op_array *op_array)
static zend_bool needs_live_range(zend_op_array *op_array, zend_op *def_opline) {
zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
zend_ssa_op *ssa_op = &func_info->ssa.ops[def_opline - op_array->opcodes];
- if (ssa_op->result_def >= 0) {
- uint32_t type = func_info->ssa.var_info[ssa_op->result_def].type;
- return (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) != 0;
+ int ssa_var = ssa_op->result_def;
+ if (ssa_var < 0) {
+ /* Be conservative. */
+ return 1;
}
- return 1;
+
+ /* If the variable is used by a PHI, this may be the assignment of the final branch of a
+ * ternary/etc structure. While this is where the live range starts, the value from the other
+ * branch may also be used. As such, use the type of the PHI node for the following check. */
+ if (func_info->ssa.vars[ssa_var].phi_use_chain) {
+ ssa_var = func_info->ssa.vars[ssa_var].phi_use_chain->ssa_var;
+ }
+
+ uint32_t type = func_info->ssa.var_info[ssa_var].type;
+ return (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) != 0;
}
#endif