3030#include "zend_inference.h"
3131#include "zend_dump.h"
3232
33- #ifndef ZEND_DEBUG_DFA
33+ // #ifndef ZEND_DEBUG_DFA
3434# define ZEND_DEBUG_DFA ZEND_DEBUG
35- #endif
35+ // #endif
3636
3737#if ZEND_DEBUG_DFA
3838# include "ssa_integrity.c"
@@ -1076,6 +1076,84 @@ static bool zend_dfa_try_to_replace_result(zend_op_array *op_array, zend_ssa *ss
10761076 return 0 ;
10771077}
10781078
1079+ static int zend_dfa_remove_only_free_uses (zend_op_array * op_array , zend_ssa * ssa )
1080+ {
1081+ int times_applied = 0 ;
1082+ for (uint32_t i = 0 ; i < op_array -> last ; i ++ ) {
1083+ zend_op * opline = op_array -> opcodes + i ;
1084+ if (opline -> opcode != ZEND_FREE ) {
1085+ continue ;
1086+ }
1087+ int op1_use = ssa -> ops [i ].op1_use ;
1088+ /* Possible if it's unreachable. */
1089+ if (op1_use < 0 ) {
1090+ continue ;
1091+ }
1092+ int definition = ssa -> vars [op1_use ].definition ;
1093+ if (definition < 0 ) {
1094+ continue ;
1095+ }
1096+ zend_op * defining_opline = op_array -> opcodes + definition ;
1097+ if (opline -> op1_type == IS_TMP_VAR ) {
1098+ switch (defining_opline -> opcode ) {
1099+ case ZEND_ASSIGN :
1100+ case ZEND_ASSIGN_DIM :
1101+ case ZEND_ASSIGN_OBJ :
1102+ case ZEND_ASSIGN_STATIC_PROP :
1103+ case ZEND_ASSIGN_OP :
1104+ case ZEND_ASSIGN_DIM_OP :
1105+ case ZEND_ASSIGN_OBJ_OP :
1106+ case ZEND_ASSIGN_STATIC_PROP_OP :
1107+ case ZEND_PRE_INC :
1108+ case ZEND_PRE_DEC :
1109+ case ZEND_PRE_INC_OBJ :
1110+ case ZEND_PRE_DEC_OBJ :
1111+ case ZEND_PRE_INC_STATIC_PROP :
1112+ case ZEND_PRE_DEC_STATIC_PROP :
1113+ break ;
1114+ default :
1115+ continue ;
1116+ }
1117+ } else if (opline -> op1_type == IS_VAR ) {
1118+ switch (defining_opline -> opcode ) {
1119+ case ZEND_FETCH_R :
1120+ case ZEND_FETCH_STATIC_PROP_R :
1121+ case ZEND_FETCH_DIM_R :
1122+ case ZEND_FETCH_OBJ_R :
1123+ case ZEND_NEW :
1124+ case ZEND_FETCH_THIS :
1125+ continue ;
1126+ default :
1127+ break ;
1128+ }
1129+ }
1130+ int use ;
1131+ bool all_free = true;
1132+ int result_def = ssa -> ops [definition ].result_def ;
1133+ if (result_def < 0 ) {
1134+ continue ;
1135+ }
1136+ FOREACH_USE (ssa -> vars + result_def , use ) {
1137+ if (op_array -> opcodes [use ].opcode != ZEND_FREE ) {
1138+ all_free = false;
1139+ break ;
1140+ }
1141+ } FOREACH_USE_END ();
1142+ if (all_free ) {
1143+ FOREACH_USE (ssa -> vars + result_def , use ) {
1144+ MAKE_NOP (op_array -> opcodes + use );
1145+ ssa -> ops [use ].op1_use_chain = -1 ;
1146+ ssa -> ops [use ].op1_use = -1 ;
1147+ } FOREACH_USE_END ();
1148+ defining_opline -> result_type = IS_UNUSED ;
1149+ zend_ssa_remove_uses_of_var (ssa , result_def );
1150+ zend_ssa_remove_result_def (ssa , ssa -> ops + definition );
1151+ times_applied ++ ;
1152+ }
1153+ }
1154+ return times_applied ;
1155+ }
1156+
10791157void zend_dfa_optimize_op_array (zend_op_array * op_array , zend_optimizer_ctx * ctx , zend_ssa * ssa , zend_call_info * * call_map )
10801158{
10811159 if (ctx -> debug_level & ZEND_DUMP_BEFORE_DFA_PASS ) {
@@ -1094,6 +1172,10 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
10941172 ssa_verify_integrity (op_array , ssa , "before dfa" );
10951173#endif
10961174
1175+ if (zend_dfa_remove_only_free_uses (op_array , ssa )) {
1176+ remove_nops = 1 ;
1177+ }
1178+
10971179 if (ZEND_OPTIMIZER_PASS_8 & ctx -> optimization_level ) {
10981180 if (sccp_optimize_op_array (ctx , op_array , ssa , call_map )) {
10991181 remove_nops = 1 ;
0 commit comments