@@ -368,6 +368,10 @@ static zend_bool try_remove_var_def(context *ctx, int free_var, int use_chain, z
368
368
return 0 ;
369
369
}
370
370
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
+
371
375
/* Returns whether the instruction has been DCEd */
372
376
static zend_bool dce_instr (context * ctx , zend_op * opline , zend_ssa_op * ssa_op ) {
373
377
zend_ssa * ssa = ctx -> ssa ;
@@ -379,24 +383,23 @@ static zend_bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
379
383
}
380
384
381
385
/* 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 )
384
387
&& !is_var_dead (ctx , ssa_op -> op1_use )) {
385
388
return 0 ;
386
389
}
387
390
388
391
if ((opline -> op1_type & (IS_VAR |IS_TMP_VAR ))&& !is_var_dead (ctx , ssa_op -> op1_use )) {
389
392
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 ) {
392
395
free_var = ssa_op -> op1_use ;
393
396
free_var_type = opline -> op1_type ;
394
397
}
395
398
}
396
399
}
397
400
if ((opline -> op2_type & (IS_VAR |IS_TMP_VAR )) && !is_var_dead (ctx , ssa_op -> op2_use )) {
398
401
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 )) {
400
403
if (free_var >= 0 ) {
401
404
// TODO: We can't free two vars. Keep instruction alive.
402
405
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
507
510
* of the producing instructions, as it combines producing the result with control flow.
508
511
* This can be made more precise if there are any cases where this is not the case. */
509
512
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 )) {
511
515
zend_bitset_excl (ctx .phi_dead , phi -> ssa_var );
512
516
add_phi_sources_to_worklists (& ctx , phi , 0 );
513
517
}
0 commit comments