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