1 /* pass 1 2 * - substitute persistent constants (true, false, null, etc) 3 * - perform compile-time evaluation of constant binary and unary operations 4 * - optimize series of ADD_STRING and/or ADD_CHAR 5 * - convert CAST(IS_BOOL,x) into BOOL(x) 6 * - convert INTI_FCALL_BY_NAME, DO_FCALL_BY_NAME into DO_FCALL 7 */ 8 9 if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { 10 int i = 0; 11 zend_op *opline = op_array->opcodes; 12 zend_op *end = opline + op_array->last; 13 14 while (opline < end) { 15 switch (opline->opcode) { 16 case ZEND_ADD: 17 case ZEND_SUB: 18 case ZEND_MUL: 19 case ZEND_DIV: 20 case ZEND_MOD: 21 case ZEND_SL: 22 case ZEND_SR: 23 case ZEND_CONCAT: 24 case ZEND_IS_EQUAL: 25 case ZEND_IS_NOT_EQUAL: 26 case ZEND_IS_SMALLER: 27 case ZEND_IS_SMALLER_OR_EQUAL: 28 case ZEND_IS_IDENTICAL: 29 case ZEND_IS_NOT_IDENTICAL: 30 case ZEND_BW_OR: 31 case ZEND_BW_AND: 32 case ZEND_BW_XOR: 33 case ZEND_BOOL_XOR: 34 if (ZEND_OP1_TYPE(opline) == IS_CONST && 35 ZEND_OP2_TYPE(opline) == IS_CONST) { 36 /* binary operation with constant operands */ 37 int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC) = get_binary_op(opline->opcode); 38 zend_uint tv = ZEND_RESULT(opline).var; /* temporary variable */ 39 zval result; 40 int er; 41 42 if (opline->opcode == ZEND_DIV && 43 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_LONG && 44 Z_LVAL(ZEND_OP2_LITERAL(opline)) == 0) { 45 /* div by 0 */ 46 break; 47 } 48 er = EG(error_reporting); 49 EG(error_reporting) = 0; 50 /* evaluate constant expression */ 51 if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline) TSRMLS_CC) != SUCCESS) { 52 EG(error_reporting) = er; 53 break; 54 } 55 EG(error_reporting) = er; 56 PZ_SET_REFCOUNT_P(&result, 1); 57 PZ_UNSET_ISREF_P(&result); 58 59 literal_dtor(&ZEND_OP1_LITERAL(opline)); 60 literal_dtor(&ZEND_OP2_LITERAL(opline)); 61 MAKE_NOP(opline); 62 63 replace_tmp_by_const(op_array, opline + 1, tv, &result TSRMLS_CC); 64 } 65 break; 66 67 case ZEND_CAST: 68 if (ZEND_OP1_TYPE(opline) == IS_CONST && 69 opline->extended_value != IS_ARRAY && 70 opline->extended_value != IS_OBJECT && 71 opline->extended_value != IS_RESOURCE) { 72 /* cast of constant operand */ 73 zend_uint tv = ZEND_RESULT(opline).var; /* temporary variable */ 74 zval res; 75 res = ZEND_OP1_LITERAL(opline); 76 zval_copy_ctor(&res); 77 switch (opline->extended_value) { 78 case IS_NULL: 79 convert_to_null(&res); 80 break; 81 case IS_BOOL: 82 convert_to_boolean(&res); 83 break; 84 case IS_LONG: 85 convert_to_long(&res); 86 break; 87 case IS_DOUBLE: 88 convert_to_double(&res); 89 break; 90 case IS_STRING: 91 convert_to_string(&res); 92 break; 93 } 94 95 literal_dtor(&ZEND_OP1_LITERAL(opline)); 96 MAKE_NOP(opline); 97 98 replace_tmp_by_const(op_array, opline + 1, tv, &res TSRMLS_CC); 99 } else if (opline->extended_value == IS_BOOL) { 100 /* T = CAST(X, IS_BOOL) => T = BOOL(X) */ 101 opline->opcode = ZEND_BOOL; 102 opline->extended_value = 0; 103 } 104 break; 105 106 case ZEND_BW_NOT: 107 case ZEND_BOOL_NOT: 108 if (ZEND_OP1_TYPE(opline) == IS_CONST) { 109 /* unary operation on constant operand */ 110 unary_op_type unary_op = get_unary_op(opline->opcode); 111 zval result; 112 zend_uint tv = ZEND_RESULT(opline).var; /* temporary variable */ 113 int er; 114 115 er = EG(error_reporting); 116 EG(error_reporting) = 0; 117 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO 118 if (unary_op(&result, &ZEND_OP1_LITERAL(opline)) != SUCCESS) { 119 #else 120 if (unary_op(&result, &ZEND_OP1_LITERAL(opline) TSRMLS_CC) != SUCCESS) { 121 #endif 122 EG(error_reporting) = er; 123 break; 124 } 125 EG(error_reporting) = er; 126 PZ_SET_REFCOUNT_P(&result, 1); 127 PZ_UNSET_ISREF_P(&result); 128 129 literal_dtor(&ZEND_OP1_LITERAL(opline)); 130 MAKE_NOP(opline); 131 132 replace_tmp_by_const(op_array, opline + 1, tv, &result TSRMLS_CC); 133 } 134 break; 135 136 case ZEND_ADD_STRING: 137 case ZEND_ADD_CHAR: 138 { 139 zend_op *next_op = opline + 1; 140 int requires_conversion = (opline->opcode == ZEND_ADD_CHAR? 1 : 0); 141 size_t final_length = 0; 142 char *ptr; 143 zend_op *last_op; 144 145 /* There is always a ZEND_RETURN at the end 146 if (next_op>=end) { 147 break; 148 } 149 */ 150 while (next_op->opcode == ZEND_ADD_STRING || next_op->opcode == ZEND_ADD_CHAR) { 151 if (ZEND_RESULT(opline).var != ZEND_RESULT(next_op).var) { 152 break; 153 } 154 if (next_op->opcode == ZEND_ADD_CHAR) { 155 final_length += 1; 156 } else { /* ZEND_ADD_STRING */ 157 final_length += ZEND_OP2_LITERAL(next_op).value.str.len; 158 } 159 next_op++; 160 } 161 if (final_length == 0) { 162 break; 163 } 164 last_op = next_op; 165 final_length += (requires_conversion? 1 : ZEND_OP2_LITERAL(opline).value.str.len); 166 ptr = (char *)emalloc(final_length + 1); 167 ptr[final_length] = '\0'; 168 if (requires_conversion) { /* ZEND_ADD_CHAR */ 169 char chval = (char)ZEND_OP2_LITERAL(opline).value.lval; 170 171 ZEND_OP2_LITERAL(opline).value.str.val = ptr; 172 ptr[0] = chval; 173 ZEND_OP2_LITERAL(opline).type = IS_STRING; 174 opline->opcode = ZEND_ADD_STRING; 175 ptr++; 176 } else { /* ZEND_ADD_STRING */ 177 memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline))); 178 if (!IS_INTERNED(Z_STRVAL(ZEND_OP2_LITERAL(opline)))) { 179 efree(Z_STRVAL(ZEND_OP2_LITERAL(opline))); 180 } 181 Z_STRVAL(ZEND_OP2_LITERAL(opline)) = ptr; 182 ptr += Z_STRLEN(ZEND_OP2_LITERAL(opline)); 183 } 184 ZEND_OP2_LITERAL(opline).value.str.len = final_length; 185 next_op = opline + 1; 186 while (next_op < last_op) { 187 if (next_op->opcode == ZEND_ADD_STRING) { 188 memcpy(ptr, ZEND_OP2_LITERAL(next_op).value.str.val, ZEND_OP2_LITERAL(next_op).value.str.len); 189 ptr += ZEND_OP2_LITERAL(next_op).value.str.len; 190 literal_dtor(&ZEND_OP2_LITERAL(next_op)); 191 } else { /* ZEND_ADD_CHAR */ 192 *ptr = (char)ZEND_OP2_LITERAL(next_op).value.lval; 193 ptr++; 194 } 195 MAKE_NOP(next_op); 196 next_op++; 197 } 198 if (!((ZEND_OPTIMIZER_PASS_5|ZEND_OPTIMIZER_PASS_10) & OPTIMIZATION_LEVEL)) { 199 /* NOP removal is disabled => insert JMP over NOPs */ 200 if (last_op-opline >= 3) { /* If we have more than 2 NOPS then JMP over them */ 201 (opline + 1)->opcode = ZEND_JMP; 202 ZEND_OP1(opline + 1).opline_num = last_op - op_array->opcodes; /* that's OK even for ZE2, since opline_num's are resolved in pass 2 later */ 203 } 204 } 205 } 206 break; 207 208 case ZEND_FETCH_CONSTANT: 209 if (ZEND_OP1_TYPE(opline) == IS_UNUSED && 210 ZEND_OP2_TYPE(opline) == IS_CONST && 211 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING && 212 Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 && 213 memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) { 214 /* substitute __COMPILER_HALT_OFFSET__ constant */ 215 zend_bool orig_in_execution = EG(in_execution); 216 zend_op_array *orig_op_array = EG(active_op_array); 217 zval offset; 218 219 EG(in_execution) = 1; 220 EG(active_op_array) = op_array; 221 if (zend_get_constant("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1, &offset TSRMLS_CC)) { 222 zend_uint tv = ZEND_RESULT(opline).var; 223 224 literal_dtor(&ZEND_OP2_LITERAL(opline)); 225 MAKE_NOP(opline); 226 replace_tmp_by_const(op_array, opline, tv, &offset TSRMLS_CC); 227 } 228 EG(active_op_array) = orig_op_array; 229 EG(in_execution) = orig_in_execution; 230 break; 231 } 232 233 if (ZEND_OP1_TYPE(opline) == IS_UNUSED && 234 ZEND_OP2_TYPE(opline) == IS_CONST && 235 ZEND_OP2_LITERAL(opline).type == IS_STRING) { 236 /* substitute persistent constants */ 237 zend_uint tv = ZEND_RESULT(opline).var; 238 zval c; 239 240 if (!zend_get_persistent_constant(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), &c, 1 TSRMLS_CC)) { 241 break; 242 } 243 literal_dtor(&ZEND_OP2_LITERAL(opline)); 244 MAKE_NOP(opline); 245 replace_tmp_by_const(op_array, opline, tv, &c TSRMLS_CC); 246 } 247 break; 248 249 case ZEND_INIT_FCALL_BY_NAME: 250 if (opline->extended_value == 0 /* not method */ && 251 ZEND_OP1_TYPE(opline) == IS_UNUSED && 252 ZEND_OP2_TYPE(opline) == IS_CONST) { 253 if ((opline + 1)->opcode == ZEND_DO_FCALL_BY_NAME && 254 (opline + 1)->extended_value == 0) { 255 (opline + 1)->opcode = ZEND_DO_FCALL; 256 COPY_NODE((opline + 1)->op1, opline->op2); 257 zend_str_tolower(Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1))); 258 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO 259 Z_HASH_P(&ZEND_OP1_LITERAL(opline + 1)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)) + 1); 260 op_array->literals[(opline + 1)->op1.constant].cache_slot = op_array->last_cache_slot++; 261 #endif 262 MAKE_NOP(opline); 263 } 264 } 265 break; 266 267 #if ZEND_EXTENSION_API_NO >= PHP_5_5_X_API_NO 268 case ZEND_FETCH_R: 269 case ZEND_FETCH_W: 270 case ZEND_FETCH_RW: 271 case ZEND_FETCH_FUNC_ARG: 272 case ZEND_FETCH_IS: 273 case ZEND_FETCH_UNSET: 274 if (opline != op_array->opcodes && 275 (opline-1)->opcode == ZEND_BEGIN_SILENCE && 276 (opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL && 277 opline->op1_type == IS_CONST && 278 opline->op2_type == IS_UNUSED && 279 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && 280 (Z_STRLEN(ZEND_OP1_LITERAL(opline)) != sizeof("this")-1 || 281 memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), "this", sizeof("this")) != 0)) { 282 283 int var = opline->result.var; 284 int level = 0; 285 zend_op *op = opline + 1; 286 zend_op *use = NULL; 287 288 while (op < end) { 289 if (op->opcode == ZEND_BEGIN_SILENCE) { 290 level++; 291 } else if (op->opcode == ZEND_END_SILENCE) { 292 if (level == 0) { 293 break; 294 } else { 295 level--; 296 } 297 } 298 if (op->op1_type == IS_VAR && op->op1.var == var) { 299 if (use) { 300 /* used more than once */ 301 use = NULL; 302 break; 303 } 304 use = op; 305 } else if (op->op2_type == IS_VAR && op->op2.var == var) { 306 if (use) { 307 /* used more than once */ 308 use = NULL; 309 break; 310 } 311 use = op; 312 } 313 op++; 314 } 315 if (use) { 316 if (use->op1_type == IS_VAR && use->op1.var == var) { 317 use->op1_type = IS_CV; 318 use->op1.var = zend_optimizer_lookup_cv(op_array, 319 Z_STRVAL(ZEND_OP1_LITERAL(opline)), 320 Z_STRLEN(ZEND_OP1_LITERAL(opline))); 321 MAKE_NOP(opline); 322 } else if (use->op2_type == IS_VAR && use->op2.var == var) { 323 use->op2_type = IS_CV; 324 use->op2.var = zend_optimizer_lookup_cv(op_array, 325 Z_STRVAL(ZEND_OP1_LITERAL(opline)), 326 Z_STRLEN(ZEND_OP1_LITERAL(opline))); 327 MAKE_NOP(opline); 328 } 329 } 330 } 331 break; 332 #endif 333 334 } 335 opline++; 336 i++; 337 } 338 } 339