@@ -1066,6 +1066,55 @@ static bool zend_dfa_try_to_replace_result(zend_op_array *op_array, zend_ssa *ss
1066
1066
return 0 ;
1067
1067
}
1068
1068
1069
+ /* Sets a flag on SEND ops when a copy can be a avoided. */
1070
+ static void zend_dfa_optimize_send_copies (zend_op_array * op_array , zend_ssa * ssa )
1071
+ {
1072
+ for (int v = 0 ; v < ssa -> vars_count ; v ++ ) {
1073
+ int var = ssa -> vars [v ].var ;
1074
+ if (var >= op_array -> last_var ) {
1075
+ continue ;
1076
+ }
1077
+
1078
+ uint32_t type = ssa -> var_info [v ].type ;
1079
+ if (!(type & (MAY_BE_ANY - (MAY_BE_RC1 |MAY_BE_ARRAY |MAY_BE_ARRAY_OF_ANY |MAY_BE_STRING |MAY_BE_NULL )))) {
1080
+ continue ;
1081
+ }
1082
+
1083
+ #if 0
1084
+ fprintf (stderr , "cv %d: " , v );
1085
+ zend_dump_var (op_array , IS_CV , v );
1086
+ fprintf (stderr , "\n" );
1087
+ fprintf (stderr , "type %x\n" , type );
1088
+ #endif
1089
+
1090
+ int use = ssa -> vars [v ].use_chain ;
1091
+ if (use >= 0
1092
+ && op_array -> opcodes [use ].opcode == ZEND_SEND_VAR
1093
+ && op_array -> opcodes [use ].op2_type == IS_UNUSED ) {
1094
+ int next_use = zend_ssa_next_use (ssa -> ops , v , use );
1095
+ #if 0
1096
+ if (next_use >= 0 && op_array -> opcodes [next_use ].opcode == ZEND_ASSIGN ) {
1097
+ fprintf (stderr , "v=%d next_use %d (%d, %d, %d, %d)\n" , v , next_use , ssa -> ops [next_use ].result_def , ssa -> ops [next_use ].result_use , ssa -> ops [next_use ].op1_use , ssa -> ops [next_use ].op2_use );
1098
+ fprintf (stderr , "next_use var: %d (var=%d)\n" , ssa -> vars [next_use ].var , var );
1099
+ fprintf (stderr , "OP1: %d (var=%d)\n" , ssa -> vars [ssa -> ops [next_use ].op1_def ].var , var );
1100
+ }
1101
+ #endif
1102
+ /* The next use must be an assignment, and there should be no uses after that.
1103
+ * If there is no next use or the next use is not an assignment, then we cannot safely
1104
+ * perform the operation without a copy because the nullified value would be observable indirectly
1105
+ * through compact(), func_get_args(), ... */
1106
+ if (next_use >= 0
1107
+ && op_array -> opcodes [next_use ].opcode == ZEND_ASSIGN
1108
+ && ssa -> ops [next_use ].op1_use == v
1109
+ && ssa -> vars [v ].var == var
1110
+ && zend_ssa_next_use (ssa -> ops , v , next_use ) < 0 ) {
1111
+ ZEND_ASSERT (op_array -> opcodes [use ].extended_value == 0 );
1112
+ op_array -> opcodes [use ].extended_value = 1 ;
1113
+ }
1114
+ }
1115
+ }
1116
+ }
1117
+
1069
1118
void zend_dfa_optimize_op_array (zend_op_array * op_array , zend_optimizer_ctx * ctx , zend_ssa * ssa , zend_call_info * * call_map )
1070
1119
{
1071
1120
if (ctx -> debug_level & ZEND_DUMP_BEFORE_DFA_PASS ) {
@@ -1124,50 +1173,9 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
1124
1173
#endif
1125
1174
}
1126
1175
1127
- // TODO: move me to other function?
1128
- for (v = 0 ; v < ssa -> vars_count && op_array -> function_name /*TODO*/ ; v ++ ) {
1129
- int var = ssa -> vars [v ].var ;
1130
- if (var >= op_array -> last_var ) {
1131
- continue ;
1132
- }
1133
-
1134
- uint32_t type = ssa -> var_info [v ].type ;
1135
- if (!(type & (MAY_BE_ANY - (MAY_BE_RC1 |MAY_BE_ARRAY |MAY_BE_ARRAY_OF_ANY |MAY_BE_STRING |MAY_BE_NULL )))) {
1136
- continue ;
1137
- }
1138
-
1139
- #if 0
1140
- fprintf (stderr , "cv %d: " , v );
1141
- zend_dump_var (op_array , IS_CV , v );
1142
- fprintf (stderr , "\n" );
1143
- fprintf (stderr , "type %x\n" , type );
1144
- #endif
1145
-
1146
- int use = ssa -> vars [v ].use_chain ;
1147
- if (use >= 0
1148
- && op_array -> opcodes [use ].opcode == ZEND_SEND_VAR
1149
- && op_array -> opcodes [use ].op2_type == IS_UNUSED ) {
1150
- int next_use = zend_ssa_next_use (ssa -> ops , v , use );
1151
- #if 0
1152
- if (next_use >= 0 && op_array -> opcodes [next_use ].opcode == ZEND_ASSIGN ) {
1153
- fprintf (stderr , "v=%d next_use %d (%d, %d, %d, %d)\n" , v , next_use , ssa -> ops [next_use ].result_def , ssa -> ops [next_use ].result_use , ssa -> ops [next_use ].op1_use , ssa -> ops [next_use ].op2_use );
1154
- fprintf (stderr , "next_use var: %d (var=%d)\n" , ssa -> vars [next_use ].var , var );
1155
- fprintf (stderr , "OP1: %d (var=%d)\n" , ssa -> vars [ssa -> ops [next_use ].op1_def ].var , var );
1156
- }
1157
- #endif
1158
- /* The next use must be an assignment, and there should be no uses after that.
1159
- * If there is no next use or the next use is not an assignment, then we cannot safely
1160
- * perform the operation without a copy because the nullified value would be observable indirectly
1161
- * through compact(), func_get_args(), ... */
1162
- if (next_use >= 0
1163
- && op_array -> opcodes [next_use ].opcode == ZEND_ASSIGN
1164
- && ssa -> ops [next_use ].op1_use == v
1165
- && ssa -> vars [v ].var == var
1166
- && zend_ssa_next_use (ssa -> ops , v , next_use ) < 0 ) {
1167
- ZEND_ASSERT (op_array -> opcodes [use ].extended_value == 0 );
1168
- op_array -> opcodes [use ].extended_value = 1 ;
1169
- }
1170
- }
1176
+ /* Optimization should not be done on main because of globals */
1177
+ if (op_array -> function_name ) {
1178
+ zend_dfa_optimize_send_copies (op_array , ssa );
1171
1179
}
1172
1180
1173
1181
for (v = op_array -> last_var ; v < ssa -> vars_count ; v ++ ) {
0 commit comments