xref: /PHP-7.0/ext/opcache/Optimizer/pass1_5.c (revision 77cbf8a6)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend OPcache                                                         |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2017 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 & 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 			if (ZEND_OP1_TYPE(opline) == IS_CONST &&
72 				ZEND_OP2_TYPE(opline) == IS_CONST) {
73 				/* binary operation with constant operands */
74 				binary_op_type binary_op = get_binary_op(opline->opcode);
75 				uint32_t tv = ZEND_RESULT(opline).var;		/* temporary variable */
76 				zval result;
77 				int er;
78 
79 				if ((opline->opcode == ZEND_DIV || opline->opcode == ZEND_MOD) &&
80 					zval_get_long(&ZEND_OP2_LITERAL(opline)) == 0) {
81 					/* div by 0 */
82 					break;
83 				} else if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR) &&
84 					zval_get_long(&ZEND_OP2_LITERAL(opline)) < 0) {
85 					/* shift by negative number */
86 					break;
87 				}
88 				er = EG(error_reporting);
89 				EG(error_reporting) = 0;
90 				/* evaluate constant expression */
91 				if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) != SUCCESS) {
92 					EG(error_reporting) = er;
93 					break;
94 				}
95 				EG(error_reporting) = er;
96 
97 				if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) {
98 					literal_dtor(&ZEND_OP1_LITERAL(opline));
99 					literal_dtor(&ZEND_OP2_LITERAL(opline));
100 					MAKE_NOP(opline);
101 				}
102 			}
103 			break;
104 
105 		case ZEND_CAST:
106 			if (ZEND_OP1_TYPE(opline) == IS_CONST &&
107 				opline->extended_value != IS_ARRAY &&
108 				opline->extended_value != IS_OBJECT &&
109 				opline->extended_value != IS_RESOURCE &&
110 				(opline->extended_value != IS_STRING
111 					|| Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_ARRAY)) {
112 				/* cast of constant operand */
113 				zend_uchar type = opline->result_type;
114 				uint32_t tv = ZEND_RESULT(opline).var;		/* temporary variable */
115 				zval res;
116 				res = ZEND_OP1_LITERAL(opline);
117 				zval_copy_ctor(&res);
118 				switch (opline->extended_value) {
119 					case IS_NULL:
120 						convert_to_null(&res);
121 						break;
122 					case _IS_BOOL:
123 						convert_to_boolean(&res);
124 						break;
125 					case IS_LONG:
126 						convert_to_long(&res);
127 						break;
128 					case IS_DOUBLE:
129 						convert_to_double(&res);
130 						break;
131 					case IS_STRING:
132 						convert_to_string(&res);
133 						break;
134 				}
135 
136 				if (zend_optimizer_replace_by_const(op_array, opline + 1, type, tv, &res)) {
137 					literal_dtor(&ZEND_OP1_LITERAL(opline));
138 					MAKE_NOP(opline);
139 				}
140 			} else if (opline->extended_value == _IS_BOOL) {
141 				/* T = CAST(X, IS_BOOL) => T = BOOL(X) */
142 				opline->opcode = ZEND_BOOL;
143 				opline->extended_value = 0;
144 			}
145 			break;
146 
147 		case ZEND_BW_NOT:
148 		case ZEND_BOOL_NOT:
149 			if (ZEND_OP1_TYPE(opline) == IS_CONST) {
150 				/* unary operation on constant operand */
151 				unary_op_type unary_op = get_unary_op(opline->opcode);
152 				zval result;
153 				uint32_t tv = ZEND_RESULT(opline).var;		/* temporary variable */
154 				int er;
155 
156 				er = EG(error_reporting);
157 				EG(error_reporting) = 0;
158 				if (unary_op(&result, &ZEND_OP1_LITERAL(opline)) != SUCCESS) {
159 					EG(error_reporting) = er;
160 					break;
161 				}
162 				EG(error_reporting) = er;
163 
164 				if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) {
165 					literal_dtor(&ZEND_OP1_LITERAL(opline));
166 					MAKE_NOP(opline);
167 				}
168 			}
169 			break;
170 
171 #if 0
172 		case ZEND_ADD_STRING:
173 		case ZEND_ADD_CHAR:
174 			{
175 				zend_op *next_op = opline + 1;
176 				int requires_conversion = (opline->opcode == ZEND_ADD_CHAR? 1 : 0);
177 				size_t final_length = 0;
178 				zend_string *str;
179 				char *ptr;
180 				zend_op *last_op;
181 
182 				/* There is always a ZEND_RETURN at the end
183 				if (next_op>=end) {
184 					break;
185 				}
186 				*/
187 				while (next_op->opcode == ZEND_ADD_STRING || next_op->opcode == ZEND_ADD_CHAR) {
188 					if (ZEND_RESULT(opline).var != ZEND_RESULT(next_op).var) {
189 						break;
190 					}
191 					if (next_op->opcode == ZEND_ADD_CHAR) {
192 						final_length += 1;
193 					} else { /* ZEND_ADD_STRING */
194 						final_length += Z_STRLEN(ZEND_OP2_LITERAL(next_op));
195 					}
196 					next_op++;
197 				}
198 				if (final_length == 0) {
199 					break;
200 				}
201 				last_op = next_op;
202 				final_length += (requires_conversion? 1 : Z_STRLEN(ZEND_OP2_LITERAL(opline)));
203 				str = zend_string_alloc(final_length, 0);
204 				str->len = final_length;
205 				ptr = str->val;
206 				ptr[final_length] = '\0';
207 				if (requires_conversion) { /* ZEND_ADD_CHAR */
208 					char chval = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
209 
210 					ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str);
211 					ptr[0] = chval;
212 					opline->opcode = ZEND_ADD_STRING;
213 					ptr++;
214 				} else { /* ZEND_ADD_STRING */
215 					memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
216 					ptr += Z_STRLEN(ZEND_OP2_LITERAL(opline));
217 					zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline)));
218 					ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str);
219 				}
220 				next_op = opline + 1;
221 				while (next_op < last_op) {
222 					if (next_op->opcode == ZEND_ADD_STRING) {
223 						memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(next_op)), Z_STRLEN(ZEND_OP2_LITERAL(next_op)));
224 						ptr += Z_STRLEN(ZEND_OP2_LITERAL(next_op));
225 						literal_dtor(&ZEND_OP2_LITERAL(next_op));
226 					} else { /* ZEND_ADD_CHAR */
227 						*ptr = (char)Z_LVAL(ZEND_OP2_LITERAL(next_op));
228 						ptr++;
229 					}
230 					MAKE_NOP(next_op);
231 					next_op++;
232 				}
233 				if (!((ZEND_OPTIMIZER_PASS_5|ZEND_OPTIMIZER_PASS_10) & OPTIMIZATION_LEVEL)) {
234 					/* NOP removal is disabled => insert JMP over NOPs */
235 					if (last_op-opline >= 3) { /* If we have more than 2 NOPS then JMP over them */
236 						(opline + 1)->opcode = ZEND_JMP;
237 						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 */
238 					}
239 				}
240 			}
241 			break;
242 #endif
243 
244 		case ZEND_FETCH_CONSTANT:
245 			if (ZEND_OP1_TYPE(opline) == IS_UNUSED &&
246 				ZEND_OP2_TYPE(opline) == IS_CONST &&
247 				Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
248 				Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 &&
249 				memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) {
250 				/* substitute __COMPILER_HALT_OFFSET__ constant */
251 				zend_execute_data *orig_execute_data = EG(current_execute_data);
252 				zend_execute_data fake_execute_data;
253 				zval *offset;
254 
255 				memset(&fake_execute_data, 0, sizeof(zend_execute_data));
256 				fake_execute_data.func = (zend_function*)op_array;
257 				EG(current_execute_data) = &fake_execute_data;
258 				if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
259 					uint32_t tv = ZEND_RESULT(opline).var;
260 
261 					if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, offset)) {
262 						literal_dtor(&ZEND_OP2_LITERAL(opline));
263 						MAKE_NOP(opline);
264 					}
265 				}
266 				EG(current_execute_data) = orig_execute_data;
267 				break;
268 			}
269 
270 			if (ZEND_OP1_TYPE(opline) == IS_UNUSED &&
271 				ZEND_OP2_TYPE(opline) == IS_CONST &&
272 				Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
273 				/* substitute persistent constants */
274 				uint32_t tv = ZEND_RESULT(opline).var;
275 				zval c;
276 
277 				if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) {
278 					if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) {
279 						break;
280 					}
281 				}
282 				if (Z_TYPE(c) == IS_CONSTANT_AST) {
283 					break;
284 				}
285 				if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) {
286 					literal_dtor(&ZEND_OP2_LITERAL(opline));
287 					MAKE_NOP(opline);
288 				}
289 			}
290 
291 			/* class constant */
292 			if (ZEND_OP1_TYPE(opline) != IS_UNUSED &&
293 			    ZEND_OP2_TYPE(opline) == IS_CONST &&
294 				Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
295 
296 				zend_class_entry *ce = NULL;
297 
298 				if (ZEND_OP1_TYPE(opline) == IS_CONST &&
299 			        Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
300 					/* for A::B */
301 					if (op_array->scope &&
302 						!strncasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)),
303 						ZSTR_VAL(op_array->scope->name), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1)) {
304 						ce = op_array->scope;
305 					} else {
306 						if ((ce = zend_hash_find_ptr(EG(class_table),
307 								Z_STR(op_array->literals[opline->op1.constant + 1]))) == NULL ||
308 								(ce->type == ZEND_INTERNAL_CLASS &&
309 								 ce->info.internal.module->type != MODULE_PERSISTENT) ||
310 								(ce->type == ZEND_USER_CLASS &&
311 								 ZEND_CE_FILENAME(ce) != op_array->filename)) {
312 							break;
313 						}
314 					}
315 				} else if (op_array->scope &&
316 					ZEND_OP1_TYPE(opline) == IS_VAR &&
317 					(opline - 1)->opcode == ZEND_FETCH_CLASS &&
318 					(ZEND_OP1_TYPE(opline - 1) == IS_UNUSED &&
319 					((opline - 1)->extended_value & ~ZEND_FETCH_CLASS_NO_AUTOLOAD) == ZEND_FETCH_CLASS_SELF) &&
320 					ZEND_RESULT((opline - 1)).var == ZEND_OP1(opline).var) {
321 					/* for self::B */
322 					ce = op_array->scope;
323 				}
324 
325 				if (ce) {
326 					uint32_t tv = ZEND_RESULT(opline).var;
327 					zval *c, t;
328 
329 					if ((c = zend_hash_find(&ce->constants_table,
330 							Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL) {
331 						ZVAL_DEREF(c);
332 						if (Z_TYPE_P(c) == IS_CONSTANT_AST) {
333 							break;
334 						}
335 						if (ZEND_IS_CONSTANT_TYPE(Z_TYPE_P(c))) {
336 							if (!zend_optimizer_get_persistent_constant(Z_STR_P(c), &t, 1) ||
337 							    ZEND_IS_CONSTANT_TYPE(Z_TYPE(t))) {
338 								break;
339 							}
340 						} else {
341 							ZVAL_COPY_VALUE(&t, c);
342 							zval_copy_ctor(&t);
343 						}
344 
345 						if (ZEND_OP1_TYPE(opline) == IS_CONST) {
346 							literal_dtor(&ZEND_OP1_LITERAL(opline));
347 						} else {
348 							MAKE_NOP((opline - 1));
349 						}
350 						if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &t)) {
351 							literal_dtor(&ZEND_OP2_LITERAL(opline));
352 							MAKE_NOP(opline);
353 						}
354 					}
355 				}
356 			}
357 			break;
358 
359 		case ZEND_DO_ICALL: {
360 			zend_op *send1_opline = opline - 1;
361 			zend_op *send2_opline = NULL;
362 			zend_op *init_opline = NULL;
363 
364 			while (send1_opline->opcode == ZEND_NOP) {
365 				send1_opline--;
366 			}
367 			if (send1_opline->opcode != ZEND_SEND_VAL ||
368 			    ZEND_OP1_TYPE(send1_opline) != IS_CONST) {
369 				/* don't colllect constants after unknown function call */
370 				collect_constants = 0;
371 				break;
372 			}
373 			if (send1_opline->op2.num == 2) {
374 				send2_opline = send1_opline;
375 				send1_opline--;
376 				while (send1_opline->opcode == ZEND_NOP) {
377 					send1_opline--;
378 				}
379 				if (send1_opline->opcode != ZEND_SEND_VAL ||
380 				    ZEND_OP1_TYPE(send1_opline) != IS_CONST) {
381 					/* don't colllect constants after unknown function call */
382 					collect_constants = 0;
383 					break;
384 				}
385 			}
386 			init_opline = send1_opline - 1;
387 			while (init_opline->opcode == ZEND_NOP) {
388 				init_opline--;
389 			}
390 			if (init_opline->opcode != ZEND_INIT_FCALL ||
391 			    ZEND_OP2_TYPE(init_opline) != IS_CONST ||
392 			    Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) {
393 				/* don't colllect constants after unknown function call */
394 				collect_constants = 0;
395 				break;
396 			}
397 
398 			/* define("name", scalar); */
399 			if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("define")-1 &&
400 			    zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), Z_STRLEN(ZEND_OP2_LITERAL(init_opline)), "define", sizeof("define")-1) == 0) {
401 
402 				if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING &&
403 				    send2_opline &&
404 				    Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) {
405 
406 					if (collect_constants) {
407 						zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline));
408 					}
409 
410 					if (RESULT_UNUSED(opline) &&
411 					    !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)))) {
412 
413 						opline->opcode = ZEND_DECLARE_CONST;
414 						opline->op1_type = IS_CONST;
415 						opline->op2_type = IS_CONST;
416 						opline->result_type = IS_UNUSED;
417 						opline->op1.constant = send1_opline->op1.constant;
418 						opline->op2.constant = send2_opline->op1.constant;
419 						opline->result.num = 0;
420 
421 						literal_dtor(&ZEND_OP2_LITERAL(init_opline));
422 						MAKE_NOP(init_opline);
423 						MAKE_NOP(send1_opline);
424 						MAKE_NOP(send2_opline);
425 					}
426 					break;
427 				}
428 			}
429 
430 			/* pre-evaluate constant functions:
431 			   defined(x)
432 			   constant(x)
433 			   function_exists(x)
434 			   is_callable(x)
435 			   extension_loaded(x)
436 			*/
437 			if (!send2_opline &&
438 			    Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) {
439 				if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 &&
440 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
441 						"function_exists", sizeof("function_exists")-1) &&
442 					!zend_optimizer_is_disabled_func("function_exists", sizeof("function_exists") - 1)) ||
443 					(Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 &&
444 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
445 						"is_callable", sizeof("is_callable")) &&
446 					!zend_optimizer_is_disabled_func("is_callable", sizeof("is_callable") - 1))) {
447 					zend_internal_function *func;
448 					zend_string *lc_name = zend_string_tolower(
449 							Z_STR(ZEND_OP1_LITERAL(send1_opline)));
450 
451 					if ((func = zend_hash_find_ptr(EG(function_table), lc_name)) != NULL
452 						 && func->type == ZEND_INTERNAL_FUNCTION
453 						 && func->module->type == MODULE_PERSISTENT
454 #ifdef ZEND_WIN32
455 						 && func->module->handle == NULL
456 #endif
457 						) {
458 						zval t;
459 						if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable") - 1 ||
460 								func->handler != ZEND_FN(display_disabled_function)) {
461 							ZVAL_TRUE(&t);
462 						} else {
463 							ZVAL_FALSE(&t);
464 						}
465 						if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
466 							literal_dtor(&ZEND_OP2_LITERAL(init_opline));
467 							MAKE_NOP(init_opline);
468 							literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
469 							MAKE_NOP(send1_opline);
470 							MAKE_NOP(opline);
471 							zend_string_release(lc_name);
472 							break;
473 						}
474 					}
475 					zend_string_release(lc_name);
476 				} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 &&
477 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
478 						"extension_loaded", sizeof("extension_loaded")-1) &&
479 					!zend_optimizer_is_disabled_func("extension_loaded", sizeof("extension_loaded") - 1)) {
480 					zval t;
481 					zend_string *lc_name = zend_string_tolower(
482 							Z_STR(ZEND_OP1_LITERAL(send1_opline)));
483 					zend_module_entry *m = zend_hash_find_ptr(&module_registry,
484 							lc_name);
485 
486 					zend_string_release(lc_name);
487 					if (!m) {
488 						if (PG(enable_dl)) {
489 							break;
490 						} else {
491 							ZVAL_FALSE(&t);
492 						}
493 					} else {
494 						if (m->type == MODULE_PERSISTENT
495 #ifdef ZEND_WIN32
496 						 && m->handle == NULL
497 #endif
498 						) {
499 							ZVAL_TRUE(&t);
500 						} else {
501 							break;
502 						}
503 					}
504 
505 					if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
506 						literal_dtor(&ZEND_OP2_LITERAL(init_opline));
507 						MAKE_NOP(init_opline);
508 						literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
509 						MAKE_NOP(send1_opline);
510 						MAKE_NOP(opline);
511 						break;
512 					}
513 				} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("defined")-1 &&
514 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
515 						"defined", sizeof("defined")-1) &&
516 					!zend_optimizer_is_disabled_func("defined", sizeof("defined") - 1)) {
517 					zval t;
518 
519 					if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 0)) {
520 
521 						ZVAL_TRUE(&t);
522 						if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
523 							literal_dtor(&ZEND_OP2_LITERAL(init_opline));
524 							MAKE_NOP(init_opline);
525 							literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
526 							MAKE_NOP(send1_opline);
527 							MAKE_NOP(opline);
528 							break;
529 						}
530 					}
531 				} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 &&
532 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
533 						"constant", sizeof("constant")-1) &&
534 					!zend_optimizer_is_disabled_func("constant", sizeof("constant") - 1)) {
535 					zval t;
536 
537 					if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) {
538 						if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
539 							literal_dtor(&ZEND_OP2_LITERAL(init_opline));
540 							MAKE_NOP(init_opline);
541 							literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
542 							MAKE_NOP(send1_opline);
543 							MAKE_NOP(opline);
544 							break;
545 						}
546 					}
547 				} else if ((CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN) == 0 &&
548 					Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("strlen") - 1 &&
549 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "strlen", sizeof("strlen") - 1) &&
550 					!zend_optimizer_is_disabled_func("strlen", sizeof("strlen") - 1)) {
551 					zval t;
552 
553 					ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)));
554 					if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
555 						literal_dtor(&ZEND_OP2_LITERAL(init_opline));
556 						MAKE_NOP(init_opline);
557 						literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
558 						MAKE_NOP(send1_opline);
559 						MAKE_NOP(opline);
560 						break;
561 					}
562 				/* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */
563 				} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 &&
564 					!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
565 						"dirname", sizeof("dirname") - 1) &&
566 					!zend_optimizer_is_disabled_func("dirname", sizeof("dirname") - 1) &&
567 					IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
568 					zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0);
569 					ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
570 					if (IS_ABSOLUTE_PATH(ZSTR_VAL(dirname), ZSTR_LEN(dirname))) {
571 						zval t;
572 
573 						ZVAL_STR(&t, dirname);
574 						if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) {
575 							literal_dtor(&ZEND_OP2_LITERAL(init_opline));
576 							MAKE_NOP(init_opline);
577 							literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
578 							MAKE_NOP(send1_opline);
579 							MAKE_NOP(opline);
580 							break;
581 						}
582 					} else {
583 						zend_string_release(dirname);
584 					}
585 				}
586 			}
587 			/* don't colllect constants after any other function call */
588 			collect_constants = 0;
589 			break;
590 		}
591 		case ZEND_STRLEN:
592 			if (ZEND_OP1_TYPE(opline) == IS_CONST &&
593 			    Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
594 				zval t;
595 
596 				ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline)));
597 				if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, ZEND_RESULT(opline).var, &t)) {
598 					literal_dtor(&ZEND_OP1_LITERAL(opline));
599 					MAKE_NOP(opline);
600 				}
601 			}
602 			break;
603 		case ZEND_DEFINED:
604 			{
605 				zval c;
606 				uint32_t tv = ZEND_RESULT(opline).var;
607 				if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) {
608 					break;
609 				}
610 				ZVAL_TRUE(&c);
611 				if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) {
612 					literal_dtor(&ZEND_OP1_LITERAL(opline));
613 					MAKE_NOP(opline);
614 				}
615 			}
616 			break;
617 		case ZEND_DECLARE_CONST:
618 			if (collect_constants &&
619 			    Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
620 			    Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) {
621 				zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline));
622 			}
623 			break;
624 
625 		case ZEND_RETURN:
626 		case ZEND_RETURN_BY_REF:
627 		case ZEND_GENERATOR_RETURN:
628 		case ZEND_EXIT:
629 		case ZEND_THROW:
630 		case ZEND_CATCH:
631 		case ZEND_FAST_CALL:
632 		case ZEND_FAST_RET:
633 		case ZEND_JMP:
634 		case ZEND_JMPZNZ:
635 		case ZEND_JMPZ:
636 		case ZEND_JMPNZ:
637 		case ZEND_JMPZ_EX:
638 		case ZEND_JMPNZ_EX:
639 		case ZEND_FE_RESET_R:
640 		case ZEND_FE_RESET_RW:
641 		case ZEND_FE_FETCH_R:
642 		case ZEND_FE_FETCH_RW:
643 		case ZEND_NEW:
644 		case ZEND_JMP_SET:
645 		case ZEND_COALESCE:
646 		case ZEND_ASSERT_CHECK:
647 			collect_constants = 0;
648 			break;
649 		case ZEND_FETCH_R:
650 		case ZEND_FETCH_W:
651 		case ZEND_FETCH_RW:
652 		case ZEND_FETCH_FUNC_ARG:
653 		case ZEND_FETCH_IS:
654 		case ZEND_FETCH_UNSET:
655 			if (opline != op_array->opcodes &&
656 			    (opline-1)->opcode == ZEND_BEGIN_SILENCE &&
657 			    (opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL &&
658 				opline->op1_type == IS_CONST &&
659 			    opline->op2_type == IS_UNUSED &&
660 			    Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
661 			    (Z_STRLEN(ZEND_OP1_LITERAL(opline)) != sizeof("this")-1 ||
662 			     memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), "this", sizeof("this") - 1) != 0)) {
663 
664 			    int var = opline->result.var;
665 			    int level = 0;
666 				zend_op *op = opline + 1;
667 				zend_op *use = NULL;
668 
669 				while (op < end) {
670 					if (op->opcode == ZEND_BEGIN_SILENCE) {
671 						level++;
672 					} else if (op->opcode == ZEND_END_SILENCE) {
673 						if (level == 0) {
674 							break;
675 						} else {
676 							level--;
677 						}
678 					}
679 					if (op->op1_type == IS_VAR && op->op1.var == var) {
680 						if (use) {
681 							/* used more than once */
682 							use = NULL;
683 							break;
684 						}
685 						use = op;
686 					} else if (op->op2_type == IS_VAR && op->op2.var == var) {
687 						if (use) {
688 							/* used more than once */
689 							use = NULL;
690 							break;
691 						}
692 						use = op;
693 					}
694 					op++;
695 				}
696 				if (use) {
697 					if (use->op1_type == IS_VAR && use->op1.var == var) {
698 						use->op1_type = IS_CV;
699 						use->op1.var = zend_optimizer_lookup_cv(op_array,
700 							Z_STR(ZEND_OP1_LITERAL(opline)));
701 						MAKE_NOP(opline);
702 					} else if (use->op2_type == IS_VAR && use->op2.var == var) {
703 						use->op2_type = IS_CV;
704 						use->op2.var = zend_optimizer_lookup_cv(op_array,
705 							Z_STR(ZEND_OP1_LITERAL(opline)));
706 						MAKE_NOP(opline);
707 					}
708 				}
709 			}
710 			break;
711 		}
712 		opline++;
713 		i++;
714 	}
715 }
716