xref: /PHP-7.2/ext/opcache/Optimizer/pass1_5.c (revision 7a7ec01a)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend OPcache                                                         |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2018 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Andi Gutmans <andi@zend.com>                                |
16    |          Zeev Suraski <zeev@zend.com>                                |
17    |          Stanislav Malyshev <stas@zend.com>                          |
18    |          Dmitry Stogov <dmitry@zend.com>                             |
19    +----------------------------------------------------------------------+
20 */
21 
22 /* pass 1
23  * - substitute persistent constants (true, false, null, etc)
24  * - perform compile-time evaluation of constant binary and unary operations
25  * - optimize series of ADD_STRING and/or ADD_CHAR
26  * - convert CAST(IS_BOOL,x) into BOOL(x)
27  * - pre-evaluate constant function calls
28  */
29 
30 #include "php.h"
31 #include "Optimizer/zend_optimizer.h"
32 #include "Optimizer/zend_optimizer_internal.h"
33 #include "zend_API.h"
34 #include "zend_constants.h"
35 #include "zend_execute.h"
36 #include "zend_vm.h"
37 
38 #define ZEND_IS_CONSTANT_TYPE(t)	((t) == IS_CONSTANT)
39 
zend_optimizer_pass1(zend_op_array * op_array,zend_optimizer_ctx * ctx)40 void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
41 {
42 	int i = 0;
43 	zend_op *opline = op_array->opcodes;
44 	zend_op *end = opline + op_array->last;
45 	zend_bool collect_constants = (ZEND_OPTIMIZER_PASS_15 & ctx->optimization_level)?
46 		(op_array == &ctx->script->main_op_array) : 0;
47 
48 	while (opline < end) {
49 		switch (opline->opcode) {
50 		case ZEND_ADD:
51 		case ZEND_SUB:
52 		case ZEND_MUL:
53 		case ZEND_DIV:
54 		case ZEND_MOD:
55 		case ZEND_POW:
56 		case ZEND_SL:
57 		case ZEND_SR:
58 		case ZEND_CONCAT:
59 		case ZEND_FAST_CONCAT:
60 		case ZEND_IS_EQUAL:
61 		case ZEND_IS_NOT_EQUAL:
62 		case ZEND_IS_SMALLER:
63 		case ZEND_IS_SMALLER_OR_EQUAL:
64 		case ZEND_IS_IDENTICAL:
65 		case ZEND_IS_NOT_IDENTICAL:
66 		case ZEND_BW_OR:
67 		case ZEND_BW_AND:
68 		case ZEND_BW_XOR:
69 		case ZEND_BOOL_XOR:
70 		case ZEND_SPACESHIP:
71 		case ZEND_CASE:
72 			if (opline->op1_type == IS_CONST &&
73 				opline->op2_type == IS_CONST) {
74 				/* binary operation with constant operands */
75 				zval result;
76 
77 				if (zend_optimizer_eval_binary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
78 					literal_dtor(&ZEND_OP1_LITERAL(opline));
79 					literal_dtor(&ZEND_OP2_LITERAL(opline));
80 					if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) {
81 						MAKE_NOP(opline);
82 					} else {
83 						opline->opcode = ZEND_QM_ASSIGN;
84 						SET_UNUSED(opline->op2);
85 						zend_optimizer_update_op1_const(op_array, opline, &result);
86 					}
87 				}
88 			}
89 			break;
90 
91 		case ZEND_CAST:
92 			if (opline->op1_type == IS_CONST) {
93 				/* cast of constant operand */
94 				zval result;
95 
96 				if (zend_optimizer_eval_cast(&result, opline->extended_value, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
97 					literal_dtor(&ZEND_OP1_LITERAL(opline));
98 					if (zend_optimizer_replace_by_const(op_array, opline + 1, opline->result_type, opline->result.var, &result)) {
99 						MAKE_NOP(opline);
100 					} else {
101 						opline->opcode = ZEND_QM_ASSIGN;
102 						opline->extended_value = 0;
103 						zend_optimizer_update_op1_const(op_array, opline, &result);
104 					}
105 					break;
106 				}
107 			}
108 
109 			if (opline->extended_value == _IS_BOOL) {
110 				/* T = CAST(X, IS_BOOL) => T = BOOL(X) */
111 				opline->opcode = ZEND_BOOL;
112 				opline->extended_value = 0;
113 			}
114 			break;
115 
116 		case ZEND_BW_NOT:
117 		case ZEND_BOOL_NOT:
118 			if (opline->op1_type == IS_CONST) {
119 				/* unary operation on constant operand */
120 				zval result;
121 
122 				if (zend_optimizer_eval_unary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
123 					literal_dtor(&ZEND_OP1_LITERAL(opline));
124 					if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) {
125 						MAKE_NOP(opline);
126 					} else {
127 						opline->opcode = ZEND_QM_ASSIGN;
128 						zend_optimizer_update_op1_const(op_array, opline, &result);
129 					}
130 				}
131 			}
132 			break;
133 
134 #if 0
135 		case ZEND_ADD_STRING:
136 		case ZEND_ADD_CHAR:
137 			{
138 				zend_op *next_op = opline + 1;
139 				int requires_conversion = (opline->opcode == ZEND_ADD_CHAR? 1 : 0);
140 				size_t final_length = 0;
141 				zend_string *str;
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 (opline->result.var != next_op->result.var) {
152 						break;
153 					}
154 					if (next_op->opcode == ZEND_ADD_CHAR) {
155 						final_length += 1;
156 					} else { /* ZEND_ADD_STRING */
157 						final_length += Z_STRLEN(ZEND_OP2_LITERAL(next_op));
158 					}
159 					next_op++;
160 				}
161 				if (final_length == 0) {
162 					break;
163 				}
164 				last_op = next_op;
165 				final_length += (requires_conversion? 1 : Z_STRLEN(ZEND_OP2_LITERAL(opline)));
166 				str = zend_string_alloc(final_length, 0);
167 				str->len = final_length;
168 				ptr = str->val;
169 				ptr[final_length] = '\0';
170 				if (requires_conversion) { /* ZEND_ADD_CHAR */
171 					char chval = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
172 
173 					ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str);
174 					ptr[0] = chval;
175 					opline->opcode = ZEND_ADD_STRING;
176 					ptr++;
177 				} else { /* ZEND_ADD_STRING */
178 					memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
179 					ptr += Z_STRLEN(ZEND_OP2_LITERAL(opline));
180 					zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline)));
181 					ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str);
182 				}
183 				next_op = opline + 1;
184 				while (next_op < last_op) {
185 					if (next_op->opcode == ZEND_ADD_STRING) {
186 						memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(next_op)), Z_STRLEN(ZEND_OP2_LITERAL(next_op)));
187 						ptr += Z_STRLEN(ZEND_OP2_LITERAL(next_op));
188 						literal_dtor(&ZEND_OP2_LITERAL(next_op));
189 					} else { /* ZEND_ADD_CHAR */
190 						*ptr = (char)Z_LVAL(ZEND_OP2_LITERAL(next_op));
191 						ptr++;
192 					}
193 					MAKE_NOP(next_op);
194 					next_op++;
195 				}
196 				if (!((ZEND_OPTIMIZER_PASS_5|ZEND_OPTIMIZER_PASS_10) & OPTIMIZATION_LEVEL)) {
197 					/* NOP removal is disabled => insert JMP over NOPs */
198 					if (last_op-opline >= 3) { /* If we have more than 2 NOPS then JMP over them */
199 						(opline + 1)->opcode = ZEND_JMP;
200 						(opline + 1)->op1.opline_num = last_op - op_array->opcodes; /* that's OK even for ZE2, since opline_num's are resolved in pass 2 later */
201 					}
202 				}
203 			}
204 			break;
205 #endif
206 
207 		case ZEND_FETCH_CONSTANT:
208 			if (opline->op2_type == IS_CONST &&
209 				Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
210 				Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 &&
211 				memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) {
212 				/* substitute __COMPILER_HALT_OFFSET__ constant */
213 				zend_execute_data *orig_execute_data = EG(current_execute_data);
214 				zend_execute_data fake_execute_data;
215 				zval *offset;
216 
217 				memset(&fake_execute_data, 0, sizeof(zend_execute_data));
218 				fake_execute_data.func = (zend_function*)op_array;
219 				EG(current_execute_data) = &fake_execute_data;
220 				if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
221 
222 					literal_dtor(&ZEND_OP2_LITERAL(opline));
223 					if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, offset)) {
224 						MAKE_NOP(opline);
225 					} else {
226 						opline->opcode = ZEND_QM_ASSIGN;
227 						opline->extended_value = 0;
228 						SET_UNUSED(opline->op2);
229 						zend_optimizer_update_op1_const(op_array, opline, offset);
230 					}
231 				}
232 				EG(current_execute_data) = orig_execute_data;
233 				break;
234 			}
235 
236 			if (opline->op2_type == IS_CONST &&
237 				Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
238 				/* substitute persistent constants */
239 				zval c;
240 
241 				if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) {
242 					if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) {
243 						break;
244 					}
245 				}
246 				if (Z_TYPE(c) == IS_CONSTANT_AST) {
247 					break;
248 				}
249 				literal_dtor(&ZEND_OP2_LITERAL(opline));
250 				if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
251 					MAKE_NOP(opline);
252 				} else {
253 					opline->opcode = ZEND_QM_ASSIGN;
254 					opline->extended_value = 0;
255 					SET_UNUSED(opline->op2);
256 					zend_optimizer_update_op1_const(op_array, opline, &c);
257 				}
258 			}
259 			break;
260 
261 		case ZEND_FETCH_CLASS_CONSTANT:
262 			if (opline->op2_type == IS_CONST &&
263 				Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
264 
265 				zend_class_entry *ce = NULL;
266 
267 				if (opline->op1_type == IS_CONST &&
268 			        Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
269 					/* for A::B */
270 					if (op_array->scope &&
271 						!strncasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)),
272 						ZSTR_VAL(op_array->scope->name), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1)) {
273 						ce = op_array->scope;
274 					} else {
275 						if ((ce = zend_hash_find_ptr(EG(class_table),
276 								Z_STR(op_array->literals[opline->op1.constant + 1]))) == NULL ||
277 								(ce->type == ZEND_INTERNAL_CLASS &&
278 								 ce->info.internal.module->type != MODULE_PERSISTENT) ||
279 								(ce->type == ZEND_USER_CLASS &&
280 								 ce->info.user.filename != op_array->filename)) {
281 							break;
282 						}
283 					}
284 				} else if (op_array->scope &&
285 					opline->op1_type == IS_UNUSED &&
286 					(opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {
287 					/* for self::B */
288 					ce = op_array->scope;
289 				} else if (op_array->scope &&
290 					opline->op1_type == IS_VAR &&
291 					(opline - 1)->opcode == ZEND_FETCH_CLASS &&
292 					((opline - 1)->op1_type == IS_UNUSED &&
293 					((opline - 1)->extended_value & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) &&
294 					(opline - 1)->result.var == opline->op1.var) {
295 					/* for self::B */
296 					ce = op_array->scope;
297 				}
298 
299 				if (ce) {
300 					zend_class_constant *cc;
301 					zval *c, t;
302 
303 					if ((cc = zend_hash_find_ptr(&ce->constants_table,
304 							Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL &&
305 						(Z_ACCESS_FLAGS(cc->value) & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
306 						c = &cc->value;
307 						if (Z_TYPE_P(c) == IS_CONSTANT_AST) {
308 							break;
309 						}
310 						if (ZEND_IS_CONSTANT_TYPE(Z_TYPE_P(c))) {
311 							if (!zend_optimizer_get_persistent_constant(Z_STR_P(c), &t, 1) ||
312 							    ZEND_IS_CONSTANT_TYPE(Z_TYPE(t))) {
313 								break;
314 							}
315 						} else {
316 							ZVAL_COPY_VALUE(&t, c);
317 							zval_copy_ctor(&t);
318 						}
319 
320 						if (opline->op1_type == IS_CONST) {
321 							literal_dtor(&ZEND_OP1_LITERAL(opline));
322 						} else if (opline->op1_type == IS_VAR) {
323 							MAKE_NOP((opline - 1));
324 						}
325 						literal_dtor(&ZEND_OP2_LITERAL(opline));
326 
327 						if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &t)) {
328 							MAKE_NOP(opline);
329 						} else {
330 							opline->opcode = ZEND_QM_ASSIGN;
331 							opline->extended_value = 0;
332 							SET_UNUSED(opline->op2);
333 							zend_optimizer_update_op1_const(op_array, opline, &t);
334 						}
335 					}
336 				}
337 			}
338 			break;
339 
340 		case ZEND_DO_ICALL: {
341 			zend_op *send1_opline = opline - 1;
342 			zend_op *send2_opline = NULL;
343 			zend_op *init_opline = NULL;
344 
345 			while (send1_opline->opcode == ZEND_NOP) {
346 				send1_opline--;
347 			}
348 			if (send1_opline->opcode != ZEND_SEND_VAL ||
349 			    send1_opline->op1_type != IS_CONST) {
350 				/* don't colllect constants after unknown function call */
351 				collect_constants = 0;
352 				break;
353 			}
354 			if (send1_opline->op2.num == 2) {
355 				send2_opline = send1_opline;
356 				send1_opline--;
357 				while (send1_opline->opcode == ZEND_NOP) {
358 					send1_opline--;
359 				}
360 				if (send1_opline->opcode != ZEND_SEND_VAL ||
361 				    send1_opline->op1_type != IS_CONST) {
362 					/* don't colllect constants after unknown function call */
363 					collect_constants = 0;
364 					break;
365 				}
366 			}
367 			init_opline = send1_opline - 1;
368 			while (init_opline->opcode == ZEND_NOP) {
369 				init_opline--;
370 			}
371 			if (init_opline->opcode != ZEND_INIT_FCALL ||
372 			    init_opline->op2_type != IS_CONST ||
373 			    Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) {
374 				/* don't colllect constants after unknown function call */
375 				collect_constants = 0;
376 				break;
377 			}
378 
379 			/* define("name", scalar); */
380 			if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("define")-1 &&
381 			    zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), Z_STRLEN(ZEND_OP2_LITERAL(init_opline)), "define", sizeof("define")-1) == 0) {
382 
383 				if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING &&
384 				    send2_opline &&
385 				    Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) {
386 
387 					if (collect_constants) {
388 						zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline));
389 					}
390 
391 					if (RESULT_UNUSED(opline) &&
392 					    !zend_memnstr(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), "::", sizeof("::") - 1, Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)) + Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
393 
394 						opline->opcode = ZEND_DECLARE_CONST;
395 						opline->op1_type = IS_CONST;
396 						opline->op2_type = IS_CONST;
397 						opline->result_type = IS_UNUSED;
398 						opline->op1.constant = send1_opline->op1.constant;
399 						opline->op2.constant = send2_opline->op1.constant;
400 						opline->result.num = 0;
401 
402 						literal_dtor(&ZEND_OP2_LITERAL(init_opline));
403 						MAKE_NOP(init_opline);
404 						MAKE_NOP(send1_opline);
405 						MAKE_NOP(send2_opline);
406 					}
407 					break;
408 				}
409 			}
410 
411 			/* pre-evaluate constant functions:
412 			   constant(x)
413 			   function_exists(x)
414 			   is_callable(x)
415 			   extension_loaded(x)
416 			*/
417 			if (!send2_opline &&
418 			    Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) {
419 				if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 &&
420 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
421 						"function_exists", sizeof("function_exists")-1) &&
422 					!zend_optimizer_is_disabled_func("function_exists", sizeof("function_exists") - 1)) ||
423 					(Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 &&
424 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
425 						"is_callable", sizeof("is_callable")) &&
426 					!zend_optimizer_is_disabled_func("is_callable", sizeof("is_callable") - 1))) {
427 					zend_internal_function *func;
428 					zend_string *lc_name = zend_string_tolower(
429 							Z_STR(ZEND_OP1_LITERAL(send1_opline)));
430 
431 					if ((func = zend_hash_find_ptr(EG(function_table), lc_name)) != NULL
432 						 && func->type == ZEND_INTERNAL_FUNCTION
433 						 && func->module->type == MODULE_PERSISTENT
434 #ifdef ZEND_WIN32
435 						 && func->module->handle == NULL
436 #endif
437 						) {
438 						zval t;
439 						if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable") - 1 ||
440 								func->handler != ZEND_FN(display_disabled_function)) {
441 							ZVAL_TRUE(&t);
442 						} else {
443 							ZVAL_FALSE(&t);
444 						}
445 						literal_dtor(&ZEND_OP2_LITERAL(init_opline));
446 						MAKE_NOP(init_opline);
447 						literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
448 						MAKE_NOP(send1_opline);
449 						if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
450 							MAKE_NOP(opline);
451 						} else {
452 							opline->opcode = ZEND_QM_ASSIGN;
453 							opline->extended_value = 0;
454 							SET_UNUSED(opline->op2);
455 							zend_optimizer_update_op1_const(op_array, opline, &t);
456 						}
457 					}
458 					zend_string_release(lc_name);
459 					break;
460 				} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 &&
461 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
462 						"extension_loaded", sizeof("extension_loaded")-1) &&
463 					!zend_optimizer_is_disabled_func("extension_loaded", sizeof("extension_loaded") - 1)) {
464 					zval t;
465 					zend_string *lc_name = zend_string_tolower(
466 							Z_STR(ZEND_OP1_LITERAL(send1_opline)));
467 					zend_module_entry *m = zend_hash_find_ptr(&module_registry,
468 							lc_name);
469 
470 					zend_string_release(lc_name);
471 					if (!m) {
472 						if (PG(enable_dl)) {
473 							break;
474 						} else {
475 							ZVAL_FALSE(&t);
476 						}
477 					} else {
478 						if (m->type == MODULE_PERSISTENT
479 #ifdef ZEND_WIN32
480 						 && m->handle == NULL
481 #endif
482 						) {
483 							ZVAL_TRUE(&t);
484 						} else {
485 							break;
486 						}
487 					}
488 
489 					literal_dtor(&ZEND_OP2_LITERAL(init_opline));
490 					MAKE_NOP(init_opline);
491 					literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
492 					MAKE_NOP(send1_opline);
493 					if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
494 						MAKE_NOP(opline);
495 					} else {
496 						opline->opcode = ZEND_QM_ASSIGN;
497 						opline->extended_value = 0;
498 						SET_UNUSED(opline->op2);
499 						zend_optimizer_update_op1_const(op_array, opline, &t);
500 					}
501 					break;
502 				} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 &&
503 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
504 						"constant", sizeof("constant")-1) &&
505 					!zend_optimizer_is_disabled_func("constant", sizeof("constant") - 1)) {
506 					zval t;
507 
508 					if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) {
509 						literal_dtor(&ZEND_OP2_LITERAL(init_opline));
510 						MAKE_NOP(init_opline);
511 						literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
512 						MAKE_NOP(send1_opline);
513 						if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
514 							MAKE_NOP(opline);
515 						} else {
516 							opline->opcode = ZEND_QM_ASSIGN;
517 							opline->extended_value = 0;
518 							SET_UNUSED(opline->op2);
519 							zend_optimizer_update_op1_const(op_array, opline, &t);
520 						}
521 					}
522 					break;
523 				/* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */
524 				} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 &&
525 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
526 						"dirname", sizeof("dirname") - 1) &&
527 					!zend_optimizer_is_disabled_func("dirname", sizeof("dirname") - 1) &&
528 					IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
529 					zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0);
530 					ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
531 					if (IS_ABSOLUTE_PATH(ZSTR_VAL(dirname), ZSTR_LEN(dirname))) {
532 						zval t;
533 
534 						ZVAL_STR(&t, dirname);
535 						literal_dtor(&ZEND_OP2_LITERAL(init_opline));
536 						MAKE_NOP(init_opline);
537 						literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
538 						MAKE_NOP(send1_opline);
539 						if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) {
540 							MAKE_NOP(opline);
541 						} else {
542 							opline->opcode = ZEND_QM_ASSIGN;
543 							opline->extended_value = 0;
544 							SET_UNUSED(opline->op2);
545 							zend_optimizer_update_op1_const(op_array, opline, &t);
546 						}
547 					} else {
548 						zend_string_release(dirname);
549 					}
550 					break;
551 				}
552 			}
553 			/* don't colllect constants after any other function call */
554 			collect_constants = 0;
555 			break;
556 		}
557 		case ZEND_STRLEN:
558 			if (opline->op1_type == IS_CONST) {
559 				zval t;
560 
561 				if (zend_optimizer_eval_strlen(&t, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
562 					literal_dtor(&ZEND_OP1_LITERAL(opline));
563 					if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &t)) {
564 						MAKE_NOP(opline);
565 					} else {
566 						opline->opcode = ZEND_QM_ASSIGN;
567 						zend_optimizer_update_op1_const(op_array, opline, &t);
568 					}
569 				}
570 			}
571 			break;
572 		case ZEND_DEFINED:
573 			{
574 				zval c;
575 				if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) {
576 					break;
577 				}
578 				ZVAL_TRUE(&c);
579 				literal_dtor(&ZEND_OP1_LITERAL(opline));
580 				if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) {
581 					MAKE_NOP(opline);
582 				} else {
583 					opline->opcode = ZEND_QM_ASSIGN;
584 					zend_optimizer_update_op1_const(op_array, opline, &c);
585 				}
586 			}
587 			break;
588 		case ZEND_DECLARE_CONST:
589 			if (collect_constants &&
590 			    Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
591 			    Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) {
592 				zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline));
593 			}
594 			break;
595 
596 		case ZEND_RETURN:
597 		case ZEND_RETURN_BY_REF:
598 		case ZEND_GENERATOR_RETURN:
599 		case ZEND_EXIT:
600 		case ZEND_THROW:
601 		case ZEND_CATCH:
602 		case ZEND_FAST_CALL:
603 		case ZEND_FAST_RET:
604 		case ZEND_JMP:
605 		case ZEND_JMPZNZ:
606 		case ZEND_JMPZ:
607 		case ZEND_JMPNZ:
608 		case ZEND_JMPZ_EX:
609 		case ZEND_JMPNZ_EX:
610 		case ZEND_FE_RESET_R:
611 		case ZEND_FE_RESET_RW:
612 		case ZEND_FE_FETCH_R:
613 		case ZEND_FE_FETCH_RW:
614 		case ZEND_JMP_SET:
615 		case ZEND_COALESCE:
616 		case ZEND_ASSERT_CHECK:
617 			collect_constants = 0;
618 			break;
619 		}
620 		opline++;
621 		i++;
622 	}
623 }
624