Skip to content

Commit 29fa4d2

Browse files
committed
Don't mark non-refcounted phi as live
If the value is not refcounted, then it doesn't matter if the FREE gets dropped.
1 parent 0826a54 commit 29fa4d2

File tree

1 file changed

+10
-6
lines changed
  • ext/opcache/Optimizer

1 file changed

+10
-6
lines changed

ext/opcache/Optimizer/dce.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,10 @@ static zend_bool try_remove_var_def(context *ctx, int free_var, int use_chain, z
368368
return 0;
369369
}
370370

371+
static zend_always_inline zend_bool may_be_refcounted(uint32_t type) {
372+
return (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) != 0;
373+
}
374+
371375
/* Returns whether the instruction has been DCEd */
372376
static zend_bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
373377
zend_ssa *ssa = ctx->ssa;
@@ -379,24 +383,23 @@ static zend_bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
379383
}
380384

381385
/* We mark FREEs as dead, but they're only really dead if the destroyed var is dead */
382-
if (opline->opcode == ZEND_FREE
383-
&& (ssa->var_info[ssa_op->op1_use].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))
386+
if (opline->opcode == ZEND_FREE && may_be_refcounted(ssa->var_info[ssa_op->op1_use].type)
384387
&& !is_var_dead(ctx, ssa_op->op1_use)) {
385388
return 0;
386389
}
387390

388391
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))&& !is_var_dead(ctx, ssa_op->op1_use)) {
389392
if (!try_remove_var_def(ctx, ssa_op->op1_use, ssa_op->op1_use_chain, opline)) {
390-
if (ssa->var_info[ssa_op->op1_use].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)
391-
&& opline->opcode != ZEND_CASE) {
393+
if (may_be_refcounted(ssa->var_info[ssa_op->op1_use].type)
394+
&& opline->opcode != ZEND_CASE) {
392395
free_var = ssa_op->op1_use;
393396
free_var_type = opline->op1_type;
394397
}
395398
}
396399
}
397400
if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && !is_var_dead(ctx, ssa_op->op2_use)) {
398401
if (!try_remove_var_def(ctx, ssa_op->op2_use, ssa_op->op2_use_chain, opline)) {
399-
if (ssa->var_info[ssa_op->op2_use].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
402+
if (may_be_refcounted(ssa->var_info[ssa_op->op2_use].type)) {
400403
if (free_var >= 0) {
401404
// TODO: We can't free two vars. Keep instruction alive.
402405
zend_bitset_excl(ctx->instr_dead, opline - ctx->op_array->opcodes);
@@ -507,7 +510,8 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_bool reor
507510
* of the producing instructions, as it combines producing the result with control flow.
508511
* This can be made more precise if there are any cases where this is not the case. */
509512
FOREACH_PHI(phi) {
510-
if (phi->var >= op_array->last_var) {
513+
if (phi->var >= op_array->last_var
514+
&& may_be_refcounted(ssa->var_info[phi->ssa_var].type)) {
511515
zend_bitset_excl(ctx.phi_dead, phi->ssa_var);
512516
add_phi_sources_to_worklists(&ctx, phi, 0);
513517
}

0 commit comments

Comments
 (0)