xref: /PHP-7.3/ext/opcache/Optimizer/block_pass.c (revision 9afce019)
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@php.net>                                 |
16    |          Zeev Suraski <zeev@php.net>                                 |
17    |          Stanislav Malyshev <stas@zend.com>                          |
18    |          Dmitry Stogov <dmitry@php.net>                              |
19    +----------------------------------------------------------------------+
20 */
21 
22 #include "php.h"
23 #include "Optimizer/zend_optimizer.h"
24 #include "Optimizer/zend_optimizer_internal.h"
25 #include "zend_API.h"
26 #include "zend_constants.h"
27 #include "zend_execute.h"
28 #include "zend_vm.h"
29 #include "zend_bitset.h"
30 #include "zend_cfg.h"
31 #include "zend_dump.h"
32 
33 /* Checks if a constant (like "true") may be replaced by its value */
zend_optimizer_get_persistent_constant(zend_string * name,zval * result,int copy)34 int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy)
35 {
36 	zend_constant *c;
37 	char *lookup_name;
38 	int retval = 1;
39 	ALLOCA_FLAG(use_heap);
40 
41 	if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) {
42 		lookup_name = do_alloca(ZSTR_LEN(name) + 1, use_heap);
43 		memcpy(lookup_name, ZSTR_VAL(name), ZSTR_LEN(name) + 1);
44 		zend_str_tolower(lookup_name, ZSTR_LEN(name));
45 
46 		if ((c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, ZSTR_LEN(name))) != NULL) {
47 			if (!(ZEND_CONSTANT_FLAGS(c) & CONST_CT_SUBST) || (ZEND_CONSTANT_FLAGS(c) & CONST_CS)) {
48 				retval = 0;
49 			}
50 		} else {
51 			retval = 0;
52 		}
53 		free_alloca(lookup_name, use_heap);
54 	}
55 
56 	if (retval) {
57 		if ((ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT)
58 		 && (!(ZEND_CONSTANT_FLAGS(c) & CONST_NO_FILE_CACHE)
59 		  || !(CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) {
60 			ZVAL_COPY_VALUE(result, &c->value);
61 			if (copy) {
62 				Z_TRY_ADDREF_P(result);
63 			}
64 		} else {
65 			retval = 0;
66 		}
67 	}
68 
69 	return retval;
70 }
71 
72 /* CFG back references management */
73 
74 #define DEL_SOURCE(from, to)
75 #define ADD_SOURCE(from, to)
76 
77 /* Data dependencies macros */
78 
79 #define VAR_NUM_EX(op) VAR_NUM((op).var)
80 
81 #define VAR_SOURCE(op) Tsource[VAR_NUM(op.var)]
82 #define SET_VAR_SOURCE(opline) Tsource[VAR_NUM(opline->result.var)] = opline
83 
84 #define convert_to_string_safe(v) \
85 	if (Z_TYPE_P((v)) == IS_NULL) { \
86 		ZVAL_STRINGL((v), "", 0); \
87 	} else { \
88 		convert_to_string((v)); \
89 	}
90 
strip_leading_nops(zend_op_array * op_array,zend_basic_block * b)91 static void strip_leading_nops(zend_op_array *op_array, zend_basic_block *b)
92 {
93 	zend_op *opcodes = op_array->opcodes;
94 
95 	while (b->len > 0 && opcodes[b->start].opcode == ZEND_NOP) {
96 	    /* check if NOP breaks incorrect smart branch */
97 		if (b->len == 2
98 		 && (op_array->opcodes[b->start + 1].opcode == ZEND_JMPZ
99 		  || op_array->opcodes[b->start + 1].opcode == ZEND_JMPNZ)
100 		 && (op_array->opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST))
101 		 && b->start > 0
102 		 && zend_is_smart_branch(op_array->opcodes + b->start - 1)) {
103 			break;
104 		}
105 		b->start++;
106 		b->len--;
107 	}
108 }
109 
strip_nops(zend_op_array * op_array,zend_basic_block * b)110 static void strip_nops(zend_op_array *op_array, zend_basic_block *b)
111 {
112 	uint32_t i, j;
113 
114 	strip_leading_nops(op_array, b);
115 	if (b->len == 0) {
116 		return;
117 	}
118 
119 	/* strip the inside NOPs */
120 	i = j = b->start + 1;
121 	while (i < b->start + b->len) {
122 		if (op_array->opcodes[i].opcode != ZEND_NOP) {
123 			if (i != j) {
124 				op_array->opcodes[j] = op_array->opcodes[i];
125 			}
126 			j++;
127 		}
128 		if (i + 1 < b->start + b->len
129 		 && (op_array->opcodes[i+1].opcode == ZEND_JMPZ
130 		  || op_array->opcodes[i+1].opcode == ZEND_JMPNZ)
131 		 && op_array->opcodes[i+1].op1_type & (IS_CV|IS_CONST)
132 		 && zend_is_smart_branch(op_array->opcodes + j - 1)) {
133 			/* don't remove NOP, that splits incorrect smart branch */
134 			j++;
135 		}
136 		i++;
137 	}
138 	b->len = j - b->start;
139 	while (j < i) {
140 		MAKE_NOP(op_array->opcodes + j);
141 		j++;
142 	}
143 }
144 
get_const_switch_target(zend_cfg * cfg,zend_op_array * op_array,zend_basic_block * block,zend_op * opline,zval * val)145 static int get_const_switch_target(zend_cfg *cfg, zend_op_array *op_array, zend_basic_block *block, zend_op *opline, zval *val) {
146 	HashTable *jumptable = Z_ARRVAL(ZEND_OP2_LITERAL(opline));
147 	zval *zv;
148 	if ((opline->opcode == ZEND_SWITCH_LONG && Z_TYPE_P(val) != IS_LONG)
149 			|| (opline->opcode == ZEND_SWITCH_STRING && Z_TYPE_P(val) != IS_STRING)) {
150 		/* fallback to next block */
151 		return block->successors[block->successors_count - 1];
152 	}
153 	if (Z_TYPE_P(val) == IS_LONG) {
154 		zv = zend_hash_index_find(jumptable, Z_LVAL_P(val));
155 	} else {
156 		ZEND_ASSERT(Z_TYPE_P(val) == IS_STRING);
157 		zv = zend_hash_find(jumptable, Z_STR_P(val));
158 	}
159 	if (!zv) {
160 		/* default */
161 		return block->successors[block->successors_count - 2];
162 	}
163 	return cfg->map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv))];
164 }
165 
zend_optimize_block(zend_basic_block * block,zend_op_array * op_array,zend_bitset used_ext,zend_cfg * cfg,zend_op ** Tsource,uint32_t * opt_count)166 static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array, zend_bitset used_ext, zend_cfg *cfg, zend_op **Tsource, uint32_t *opt_count)
167 {
168 	zend_op *opline, *src;
169 	zend_op *end, *last_op = NULL;
170 
171 	/* remove leading NOPs */
172 	strip_leading_nops(op_array, block);
173 
174 	opline = op_array->opcodes + block->start;
175 	end = opline + block->len;
176 	while (opline < end) {
177 		/* Constant Propagation: strip X = QM_ASSIGN(const) */
178 		if ((opline->op1_type & (IS_TMP_VAR|IS_VAR)) &&
179 		    opline->opcode != ZEND_FREE) {
180 			src = VAR_SOURCE(opline->op1);
181 			if (src &&
182 			    src->opcode == ZEND_QM_ASSIGN &&
183 			    src->op1_type == IS_CONST
184 			) {
185 				znode_op op1 = opline->op1;
186 				if (opline->opcode == ZEND_VERIFY_RETURN_TYPE) {
187 					zend_optimizer_remove_live_range(op_array, op1.var);
188 					COPY_NODE(opline->result, opline->op1);
189 					COPY_NODE(opline->op1, src->op1);
190 					VAR_SOURCE(op1) = NULL;
191 					MAKE_NOP(src);
192 					++(*opt_count);
193 				} else {
194 					zval c;
195 					ZVAL_COPY(&c, &ZEND_OP1_LITERAL(src));
196 					if (zend_optimizer_update_op1_const(op_array, opline, &c)) {
197 						zend_optimizer_remove_live_range(op_array, op1.var);
198 						VAR_SOURCE(op1) = NULL;
199 						literal_dtor(&ZEND_OP1_LITERAL(src));
200 						MAKE_NOP(src);
201 						++(*opt_count);
202 						switch (opline->opcode) {
203 							case ZEND_JMPZ:
204 								if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
205 									MAKE_NOP(opline);
206 									DEL_SOURCE(block, block->successors[0]);
207 									block->successors_count = 1;
208 									block->successors[0] = block->successors[1];
209 								} else {
210 									opline->opcode = ZEND_JMP;
211 									COPY_NODE(opline->op1, opline->op2);
212 									DEL_SOURCE(block, block->successors[1]);
213 									block->successors_count = 1;
214 								}
215 								break;
216 							case ZEND_JMPNZ:
217 								if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
218 									opline->opcode = ZEND_JMP;
219 									COPY_NODE(opline->op1, opline->op2);
220 									DEL_SOURCE(block, block->successors[1]);
221 									block->successors_count = 1;
222 								} else {
223 									MAKE_NOP(opline);
224 									DEL_SOURCE(block, block->successors[0]);
225 									block->successors_count = 1;
226 									block->successors[0] = block->successors[1];
227 								}
228 								break;
229 							case ZEND_JMPZNZ:
230 								if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
231 									zend_op *target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
232 									ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
233 									DEL_SOURCE(block, block->successors[0]);
234 									block->successors[0] = block->successors[1];
235 								} else {
236 									zend_op *target_opline = ZEND_OP2_JMP_ADDR(opline);
237 									ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
238 									DEL_SOURCE(block, block->successors[0]);
239 								}
240 								block->successors_count = 1;
241 								opline->op1_type = IS_UNUSED;
242 								opline->extended_value = 0;
243 								opline->opcode = ZEND_JMP;
244 								break;
245 							default:
246 								break;
247 						}
248 					} else {
249 						zval_ptr_dtor_nogc(&c);
250 					}
251 				}
252 			}
253 		}
254 
255 		/* Constant Propagation: strip X = QM_ASSIGN(const) */
256 		if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
257 			src = VAR_SOURCE(opline->op2);
258 			if (src &&
259 			    src->opcode == ZEND_QM_ASSIGN &&
260 			    src->op1_type == IS_CONST) {
261 
262 				znode_op op2 = opline->op2;
263 				zval c;
264 
265 				ZVAL_COPY(&c, &ZEND_OP1_LITERAL(src));
266 				if (zend_optimizer_update_op2_const(op_array, opline, &c)) {
267 					zend_optimizer_remove_live_range(op_array, op2.var);
268 					VAR_SOURCE(op2) = NULL;
269 					literal_dtor(&ZEND_OP1_LITERAL(src));
270 					MAKE_NOP(src);
271 					++(*opt_count);
272 				} else {
273 					zval_ptr_dtor_nogc(&c);
274 				}
275 			}
276 		}
277 
278 		if (opline->opcode == ZEND_ECHO) {
279 			if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
280 				src = VAR_SOURCE(opline->op1);
281 				if (src &&
282 				    src->opcode == ZEND_CAST &&
283 				    src->extended_value == IS_STRING) {
284 					/* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */
285 					zend_optimizer_remove_live_range(op_array, opline->op1.var);
286 					VAR_SOURCE(opline->op1) = NULL;
287 					COPY_NODE(opline->op1, src->op1);
288 					MAKE_NOP(src);
289 					++(*opt_count);
290 				}
291 			}
292 
293 			if (opline->op1_type == IS_CONST) {
294 				if (last_op && last_op->opcode == ZEND_ECHO &&
295 				    last_op->op1_type == IS_CONST &&
296 				    Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_DOUBLE &&
297 				    Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_DOUBLE) {
298 					/* compress consecutive ECHO's.
299 					 * Float to string conversion may be affected by current
300 					 * locale setting.
301 					 */
302 					int l, old_len;
303 
304 					if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
305 						convert_to_string_safe(&ZEND_OP1_LITERAL(opline));
306 					}
307 					if (Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_STRING) {
308 						convert_to_string_safe(&ZEND_OP1_LITERAL(last_op));
309 					}
310 					old_len = Z_STRLEN(ZEND_OP1_LITERAL(last_op));
311 					l = old_len + Z_STRLEN(ZEND_OP1_LITERAL(opline));
312 					if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(last_op))) {
313 						zend_string *tmp = zend_string_alloc(l, 0);
314 						memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP1_LITERAL(last_op)), old_len);
315 						Z_STR(ZEND_OP1_LITERAL(last_op)) = tmp;
316 					} else {
317 						Z_STR(ZEND_OP1_LITERAL(last_op)) = zend_string_extend(Z_STR(ZEND_OP1_LITERAL(last_op)), l, 0);
318 					}
319 					Z_TYPE_INFO(ZEND_OP1_LITERAL(last_op)) = IS_STRING_EX;
320 					memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op)) + old_len, Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)));
321 					Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0';
322 					zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
323 					ZVAL_STR(&ZEND_OP1_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op))));
324 					ZVAL_NULL(&ZEND_OP1_LITERAL(last_op));
325 					MAKE_NOP(last_op);
326 					++(*opt_count);
327 				}
328 				last_op = opline;
329 			} else {
330 				last_op = NULL;
331 			}
332 		} else {
333 			last_op = NULL;
334 		}
335 
336 		switch (opline->opcode) {
337 
338 			case ZEND_FREE:
339 				if (opline->op1_type == IS_TMP_VAR) {
340 					src = VAR_SOURCE(opline->op1);
341 					if (src &&
342 					    (src->opcode == ZEND_BOOL || src->opcode == ZEND_BOOL_NOT)) {
343 						/* T = BOOL(X), FREE(T) => T = BOOL(X) */
344 						/* The remaining BOOL is removed by a separate optimization */
345 						VAR_SOURCE(opline->op1) = NULL;
346 						MAKE_NOP(opline);
347 						++(*opt_count);
348 					}
349 				} else if (opline->op1_type == IS_VAR) {
350 					src = VAR_SOURCE(opline->op1);
351 					/* V = OP, FREE(V) => OP. NOP */
352 					if (src &&
353 					    src->opcode != ZEND_FETCH_R &&
354 					    src->opcode != ZEND_FETCH_STATIC_PROP_R &&
355 					    src->opcode != ZEND_FETCH_DIM_R &&
356 					    src->opcode != ZEND_FETCH_OBJ_R &&
357 					    src->opcode != ZEND_NEW) {
358 						src->result_type = IS_UNUSED;
359 						MAKE_NOP(opline);
360 						++(*opt_count);
361 					}
362 				}
363 				break;
364 
365 #if 0
366 		/* pre-evaluate functions:
367 		   constant(x)
368 		   function_exists(x)
369 		   extension_loaded(x)
370 		   BAD: interacts badly with Accelerator
371 		*/
372 		if((opline->op1_type & IS_VAR) &&
373 		   VAR_SOURCE(opline->op1) && VAR_SOURCE(opline->op1)->opcode == ZEND_DO_CF_FCALL &&
374 		   VAR_SOURCE(opline->op1)->extended_value == 1) {
375 			zend_op *fcall = VAR_SOURCE(opline->op1);
376 			zend_op *sv = fcall-1;
377 			if(sv >= block->start_opline && sv->opcode == ZEND_SEND_VAL &&
378 			   sv->op1_type == IS_CONST && Z_TYPE(OPLINE_OP1_LITERAL(sv)) == IS_STRING &&
379 			   Z_LVAL(OPLINE_OP2_LITERAL(sv)) == 1
380 			   ) {
381 				zval *arg = &OPLINE_OP1_LITERAL(sv);
382 				char *fname = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].function_name;
383 				int flen = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].name_len;
384 				if((flen == sizeof("function_exists")-1 && zend_binary_strcasecmp(fname, flen, "function_exists", sizeof("function_exists")-1) == 0) ||
385 						  (flen == sizeof("is_callable")-1 && zend_binary_strcasecmp(fname, flen, "is_callable", sizeof("is_callable")-1) == 0)
386 						  ) {
387 					zend_function *function;
388 					if((function = zend_hash_find_ptr(EG(function_table), Z_STR_P(arg))) != NULL) {
389 						literal_dtor(arg);
390 						MAKE_NOP(sv);
391 						MAKE_NOP(fcall);
392 						LITERAL_BOOL(opline->op1, 1);
393 						opline->op1_type = IS_CONST;
394 					}
395 				} else if(flen == sizeof("constant")-1 && zend_binary_strcasecmp(fname, flen, "constant", sizeof("constant")-1) == 0) {
396 					zval c;
397 					if(zend_optimizer_get_persistent_constant(Z_STR_P(arg), &c, 1 ELS_CC) != 0) {
398 						literal_dtor(arg);
399 						MAKE_NOP(sv);
400 						MAKE_NOP(fcall);
401 						ZEND_OP1_LITERAL(opline) = zend_optimizer_add_literal(op_array, &c);
402 						/* no copy ctor - get already copied it */
403 						opline->op1_type = IS_CONST;
404 					}
405 				} else if(flen == sizeof("extension_loaded")-1 && zend_binary_strcasecmp(fname, flen, "extension_loaded", sizeof("extension_loaded")-1) == 0) {
406 					if(zend_hash_exists(&module_registry, Z_STR_P(arg))) {
407 						literal_dtor(arg);
408 						MAKE_NOP(sv);
409 						MAKE_NOP(fcall);
410 						LITERAL_BOOL(opline->op1, 1);
411 						opline->op1_type = IS_CONST;
412 					}
413 				}
414 			}
415 		}
416 #endif
417 
418 			case ZEND_FETCH_LIST_R:
419 			case ZEND_FETCH_LIST_W:
420 				if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
421 					/* LIST variable will be deleted later by FREE */
422 					Tsource[VAR_NUM(opline->op1.var)] = NULL;
423 				}
424 				break;
425 
426 			case ZEND_SWITCH_LONG:
427 			case ZEND_SWITCH_STRING:
428 				if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
429 					/* SWITCH variable will be deleted later by FREE, so we can't optimize it */
430 					Tsource[VAR_NUM(opline->op1.var)] = NULL;
431 					break;
432 				}
433 				if (opline->op1_type == IS_CONST) {
434 					int target = get_const_switch_target(cfg, op_array, block, opline, &ZEND_OP1_LITERAL(opline));
435 					literal_dtor(&ZEND_OP1_LITERAL(opline));
436 					literal_dtor(&ZEND_OP2_LITERAL(opline));
437 					opline->opcode = ZEND_JMP;
438 					opline->op1_type = IS_UNUSED;
439 					opline->op2_type = IS_UNUSED;
440 					block->successors_count = 1;
441 					block->successors[0] = target;
442 				}
443 				break;
444 
445 			case ZEND_CASE:
446 				if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
447 					/* CASE variable will be deleted later by FREE, so we can't optimize it */
448 					Tsource[VAR_NUM(opline->op1.var)] = NULL;
449 					break;
450 				}
451 				/* break missing intentionally */
452 
453 			case ZEND_IS_EQUAL:
454 			case ZEND_IS_NOT_EQUAL:
455 				if (opline->op1_type == IS_CONST &&
456 				    opline->op2_type == IS_CONST) {
457 					goto optimize_constant_binary_op;
458 				}
459 		        /* IS_EQ(TRUE, X)      => BOOL(X)
460 		         * IS_EQ(FALSE, X)     => BOOL_NOT(X)
461 		         * IS_NOT_EQ(TRUE, X)  => BOOL_NOT(X)
462 		         * IS_NOT_EQ(FALSE, X) => BOOL(X)
463 		         * CASE(TRUE, X)       => BOOL(X)
464 		         * CASE(FALSE, X)      => BOOL_NOT(X)
465 		         */
466 				if (opline->op1_type == IS_CONST &&
467 					(Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_FALSE ||
468 					 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_TRUE)) {
469 					/* Optimization of comparison with "null" is not safe,
470 					 * because ("0" == null) is not equal to !("0")
471 					 */
472 					opline->opcode =
473 						((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP1_LITERAL(opline))) == IS_TRUE)) ?
474 						ZEND_BOOL : ZEND_BOOL_NOT;
475 					COPY_NODE(opline->op1, opline->op2);
476 					SET_UNUSED(opline->op2);
477 					++(*opt_count);
478 					goto optimize_bool;
479 				} else if (opline->op2_type == IS_CONST &&
480 				           (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_FALSE ||
481 				            Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_TRUE)) {
482 					/* Optimization of comparison with "null" is not safe,
483 					 * because ("0" == null) is not equal to !("0")
484 					 */
485 					opline->opcode =
486 						((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP2_LITERAL(opline))) == IS_TRUE)) ?
487 						ZEND_BOOL : ZEND_BOOL_NOT;
488 					SET_UNUSED(opline->op2);
489 					++(*opt_count);
490 					goto optimize_bool;
491 				}
492 				break;
493 
494 			case ZEND_BOOL:
495 			case ZEND_BOOL_NOT:
496 			optimize_bool:
497 				if (opline->op1_type == IS_CONST) {
498 					goto optimize_const_unary_op;
499 				}
500 				if (opline->op1_type == IS_TMP_VAR &&
501 				    !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
502 					src = VAR_SOURCE(opline->op1);
503 					if (src) {
504 						switch (src->opcode) {
505 							case ZEND_BOOL_NOT:
506 								/* T = BOOL_NOT(X) + BOOL(T) -> NOP, BOOL_NOT(X) */
507 								VAR_SOURCE(opline->op1) = NULL;
508 								COPY_NODE(opline->op1, src->op1);
509 								opline->opcode = (opline->opcode == ZEND_BOOL) ? ZEND_BOOL_NOT : ZEND_BOOL;
510 								MAKE_NOP(src);
511 								++(*opt_count);
512 								goto optimize_bool;
513 							case ZEND_BOOL:
514 								/* T = BOOL(X) + BOOL(T) -> NOP, BOOL(X) */
515 								VAR_SOURCE(opline->op1) = NULL;
516 								COPY_NODE(opline->op1, src->op1);
517 								MAKE_NOP(src);
518 								++(*opt_count);
519 								goto optimize_bool;
520 							case ZEND_IS_EQUAL:
521 								if (opline->opcode == ZEND_BOOL_NOT) {
522 									src->opcode = ZEND_IS_NOT_EQUAL;
523 								}
524 								COPY_NODE(src->result, opline->result);
525 								SET_VAR_SOURCE(src);
526 								MAKE_NOP(opline);
527 								++(*opt_count);
528 								break;
529 							case ZEND_IS_NOT_EQUAL:
530 								if (opline->opcode == ZEND_BOOL_NOT) {
531 									src->opcode = ZEND_IS_EQUAL;
532 								}
533 								COPY_NODE(src->result, opline->result);
534 								SET_VAR_SOURCE(src);
535 								MAKE_NOP(opline);
536 								++(*opt_count);
537 								break;
538 							case ZEND_IS_IDENTICAL:
539 								if (opline->opcode == ZEND_BOOL_NOT) {
540 									src->opcode = ZEND_IS_NOT_IDENTICAL;
541 								}
542 								COPY_NODE(src->result, opline->result);
543 								SET_VAR_SOURCE(src);
544 								MAKE_NOP(opline);
545 								++(*opt_count);
546 								break;
547 							case ZEND_IS_NOT_IDENTICAL:
548 								if (opline->opcode == ZEND_BOOL_NOT) {
549 									src->opcode = ZEND_IS_IDENTICAL;
550 								}
551 								COPY_NODE(src->result, opline->result);
552 								SET_VAR_SOURCE(src);
553 								MAKE_NOP(opline);
554 								++(*opt_count);
555 								break;
556 							case ZEND_IS_SMALLER:
557 								if (opline->opcode == ZEND_BOOL_NOT) {
558 									zend_uchar tmp_type;
559 									uint32_t tmp;
560 
561 									src->opcode = ZEND_IS_SMALLER_OR_EQUAL;
562 									tmp_type = src->op1_type;
563 									src->op1_type = src->op2_type;
564 									src->op2_type = tmp_type;
565 									tmp = src->op1.num;
566 									src->op1.num = src->op2.num;
567 									src->op2.num = tmp;
568 								}
569 								COPY_NODE(src->result, opline->result);
570 								SET_VAR_SOURCE(src);
571 								MAKE_NOP(opline);
572 								++(*opt_count);
573 								break;
574 							case ZEND_IS_SMALLER_OR_EQUAL:
575 								if (opline->opcode == ZEND_BOOL_NOT) {
576 									zend_uchar tmp_type;
577 									uint32_t tmp;
578 
579 									src->opcode = ZEND_IS_SMALLER;
580 									tmp_type = src->op1_type;
581 									src->op1_type = src->op2_type;
582 									src->op2_type = tmp_type;
583 									tmp = src->op1.num;
584 									src->op1.num = src->op2.num;
585 									src->op2.num = tmp;
586 								}
587 								COPY_NODE(src->result, opline->result);
588 								SET_VAR_SOURCE(src);
589 								MAKE_NOP(opline);
590 								++(*opt_count);
591 								break;
592 							case ZEND_ISSET_ISEMPTY_VAR:
593 							case ZEND_ISSET_ISEMPTY_DIM_OBJ:
594 							case ZEND_ISSET_ISEMPTY_PROP_OBJ:
595 							case ZEND_ISSET_ISEMPTY_STATIC_PROP:
596 							case ZEND_INSTANCEOF:
597 							case ZEND_TYPE_CHECK:
598 							case ZEND_DEFINED:
599 							case ZEND_IN_ARRAY:
600 								if (opline->opcode == ZEND_BOOL_NOT) {
601 									break;
602 								}
603 								COPY_NODE(src->result, opline->result);
604 								SET_VAR_SOURCE(src);
605 								MAKE_NOP(opline);
606 								++(*opt_count);
607 								break;
608 						}
609 					}
610 				}
611 				break;
612 
613 			case ZEND_JMPZ:
614 			case ZEND_JMPNZ:
615 			case ZEND_JMPZ_EX:
616 			case ZEND_JMPNZ_EX:
617 			case ZEND_JMPZNZ:
618 			optimize_jmpznz:
619 				if (opline->op1_type == IS_TMP_VAR &&
620 				    (!zend_bitset_in(used_ext, VAR_NUM(opline->op1.var)) ||
621 				     (opline->result_type == opline->op1_type &&
622 				      opline->result.var == opline->op1.var))) {
623 					src = VAR_SOURCE(opline->op1);
624 					if (src) {
625 						if (src->opcode == ZEND_BOOL_NOT &&
626 						    opline->opcode != ZEND_JMPZ_EX &&
627 						    opline->opcode != ZEND_JMPNZ_EX) {
628 							VAR_SOURCE(opline->op1) = NULL;
629 							COPY_NODE(opline->op1, src->op1);
630 							if (opline->opcode == ZEND_JMPZ) {
631 								/* T = BOOL_NOT(X) + JMPZ(T) -> NOP, JMPNZ(X) */
632 								opline->opcode = ZEND_JMPNZ;
633 							} else if (opline->opcode == ZEND_JMPNZ) {
634 								/* T = BOOL_NOT(X) + JMPNZ(T) -> NOP, JMPZ(X) */
635 								opline->opcode = ZEND_JMPZ;
636 #if 0
637 							} else if (opline->opcode == ZEND_JMPZ_EX) {
638 								/* T = BOOL_NOT(X) + JMPZ_EX(T) -> NOP, JMPNZ_EX(X) */
639 								opline->opcode = ZEND_JMPNZ_EX;
640 							} else if (opline->opcode == ZEND_JMPNZ_EX) {
641 								/* T = BOOL_NOT(X) + JMPNZ_EX(T) -> NOP, JMPZ_EX(X) */
642 								opline->opcode = ZEND_JMPZ;
643 #endif
644 							} else {
645 								/* T = BOOL_NOT(X) + JMPZNZ(T,L1,L2) -> NOP, JMPZNZ(X,L2,L1) */
646 								uint32_t tmp;
647 
648 								ZEND_ASSERT(opline->opcode == ZEND_JMPZNZ);
649 								tmp = block->successors[0];
650 								block->successors[0] = block->successors[1];
651 								block->successors[1] = tmp;
652 							}
653 							MAKE_NOP(src);
654 							++(*opt_count);
655 							goto optimize_jmpznz;
656 						} else if (src->opcode == ZEND_BOOL ||
657 						           src->opcode == ZEND_QM_ASSIGN) {
658 							VAR_SOURCE(opline->op1) = NULL;
659 							COPY_NODE(opline->op1, src->op1);
660 							MAKE_NOP(src);
661 							++(*opt_count);
662 							goto optimize_jmpznz;
663 						}
664 					}
665 				}
666 				break;
667 
668 			case ZEND_CONCAT:
669 			case ZEND_FAST_CONCAT:
670 				if (opline->op1_type == IS_CONST &&
671 				    opline->op2_type == IS_CONST) {
672 					goto optimize_constant_binary_op;
673 				}
674 
675 				if (opline->op2_type == IS_CONST &&
676 				    opline->op1_type == IS_TMP_VAR) {
677 
678 					src = VAR_SOURCE(opline->op1);
679 				    if (src &&
680 					    (src->opcode == ZEND_CONCAT ||
681 					     src->opcode == ZEND_FAST_CONCAT) &&
682 					    src->op2_type == IS_CONST) {
683 						/* compress consecutive CONCATs */
684 						int l, old_len;
685 
686 						if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
687 							convert_to_string_safe(&ZEND_OP2_LITERAL(opline));
688 						}
689 						if (Z_TYPE(ZEND_OP2_LITERAL(src)) != IS_STRING) {
690 							convert_to_string_safe(&ZEND_OP2_LITERAL(src));
691 						}
692 
693 						VAR_SOURCE(opline->op1) = NULL;
694 						COPY_NODE(opline->op1, src->op1);
695 						old_len = Z_STRLEN(ZEND_OP2_LITERAL(src));
696 						l = old_len + Z_STRLEN(ZEND_OP2_LITERAL(opline));
697 						if (!Z_REFCOUNTED(ZEND_OP2_LITERAL(src))) {
698 							zend_string *tmp = zend_string_alloc(l, 0);
699 							memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP2_LITERAL(src)), old_len);
700 							Z_STR(ZEND_OP2_LITERAL(src)) = tmp;
701 						} else {
702 							Z_STR(ZEND_OP2_LITERAL(src)) = zend_string_extend(Z_STR(ZEND_OP2_LITERAL(src)), l, 0);
703 						}
704 						Z_TYPE_INFO(ZEND_OP2_LITERAL(src)) = IS_STRING_EX;
705 						memcpy(Z_STRVAL(ZEND_OP2_LITERAL(src)) + old_len, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
706 						Z_STRVAL(ZEND_OP2_LITERAL(src))[l] = '\0';
707 						zval_ptr_dtor_str(&ZEND_OP2_LITERAL(opline));
708 						ZVAL_STR(&ZEND_OP2_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP2_LITERAL(src))));
709 						ZVAL_NULL(&ZEND_OP2_LITERAL(src));
710 						MAKE_NOP(src);
711 						++(*opt_count);
712 					}
713 				}
714 
715 				if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
716 					src = VAR_SOURCE(opline->op1);
717 					if (src &&
718 					    src->opcode == ZEND_CAST &&
719 					    src->extended_value == IS_STRING) {
720 						/* convert T1 = CAST(STRING, X), T2 = CONCAT(T1, Y) to T2 = CONCAT(X,Y) */
721 						zend_optimizer_remove_live_range(op_array, opline->op1.var);
722 						VAR_SOURCE(opline->op1) = NULL;
723 						COPY_NODE(opline->op1, src->op1);
724 						MAKE_NOP(src);
725 						++(*opt_count);
726 					}
727 	            }
728 				if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
729 					src = VAR_SOURCE(opline->op2);
730 					if (src &&
731 					    src->opcode == ZEND_CAST &&
732 					    src->extended_value == IS_STRING) {
733 						/* convert T1 = CAST(STRING, X), T2 = CONCAT(Y, T1) to T2 = CONCAT(Y,X) */
734 						zend_optimizer_remove_live_range(op_array, opline->op2.var);
735 						zend_op *src = VAR_SOURCE(opline->op2);
736 						VAR_SOURCE(opline->op2) = NULL;
737 						COPY_NODE(opline->op2, src->op1);
738 						MAKE_NOP(src);
739 						++(*opt_count);
740 					}
741 				}
742 				if (opline->op1_type == IS_CONST &&
743 				    Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
744 				    Z_STRLEN(ZEND_OP1_LITERAL(opline)) == 0) {
745 					/* convert CONCAT('', X) => CAST(STRING, X) */
746 					literal_dtor(&ZEND_OP1_LITERAL(opline));
747 					opline->opcode = ZEND_CAST;
748 					opline->extended_value = IS_STRING;
749 					COPY_NODE(opline->op1, opline->op2);
750 					opline->op2_type = IS_UNUSED;
751 					opline->op2.var = 0;
752 					++(*opt_count);
753 				} else if (opline->op2_type == IS_CONST &&
754 			           Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
755 			           Z_STRLEN(ZEND_OP2_LITERAL(opline)) == 0) {
756 					/* convert CONCAT(X, '') => CAST(STRING, X) */
757 					literal_dtor(&ZEND_OP2_LITERAL(opline));
758 					opline->opcode = ZEND_CAST;
759 					opline->extended_value = IS_STRING;
760 					opline->op2_type = IS_UNUSED;
761 					opline->op2.var = 0;
762 					++(*opt_count);
763 				} else if (opline->opcode == ZEND_CONCAT &&
764 				           (opline->op1_type == IS_CONST ||
765 				            (opline->op1_type == IS_TMP_VAR &&
766 				             VAR_SOURCE(opline->op1) &&
767 				             (VAR_SOURCE(opline->op1)->opcode == ZEND_FAST_CONCAT ||
768 				              VAR_SOURCE(opline->op1)->opcode == ZEND_ROPE_END ||
769 				              VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CONSTANT ||
770 				              VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CLASS_CONSTANT))) &&
771 				           (opline->op2_type == IS_CONST ||
772 				            (opline->op2_type == IS_TMP_VAR &&
773 				             VAR_SOURCE(opline->op2) &&
774 				             (VAR_SOURCE(opline->op2)->opcode == ZEND_FAST_CONCAT ||
775 				              VAR_SOURCE(opline->op2)->opcode == ZEND_ROPE_END ||
776 				              VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CONSTANT ||
777 				              VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CLASS_CONSTANT)))) {
778 					opline->opcode = ZEND_FAST_CONCAT;
779 					++(*opt_count);
780 				}
781 				break;
782 
783 			case ZEND_ADD:
784 			case ZEND_SUB:
785 			case ZEND_MUL:
786 			case ZEND_DIV:
787 			case ZEND_MOD:
788 			case ZEND_SL:
789 			case ZEND_SR:
790 			case ZEND_IS_SMALLER:
791 			case ZEND_IS_SMALLER_OR_EQUAL:
792 			case ZEND_IS_IDENTICAL:
793 			case ZEND_IS_NOT_IDENTICAL:
794 			case ZEND_BOOL_XOR:
795 			case ZEND_BW_OR:
796 			case ZEND_BW_AND:
797 			case ZEND_BW_XOR:
798 				if (opline->op1_type == IS_CONST &&
799 				    opline->op2_type == IS_CONST) {
800 					/* evaluate constant expressions */
801 					zval result;
802 
803 optimize_constant_binary_op:
804 					if (zend_optimizer_eval_binary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
805 						literal_dtor(&ZEND_OP1_LITERAL(opline));
806 						literal_dtor(&ZEND_OP2_LITERAL(opline));
807 						opline->opcode = ZEND_QM_ASSIGN;
808 						SET_UNUSED(opline->op2);
809 						zend_optimizer_update_op1_const(op_array, opline, &result);
810 						++(*opt_count);
811 					}
812 				}
813 				break;
814 
815 			case ZEND_BW_NOT:
816 				if (opline->op1_type == IS_CONST) {
817 					/* evaluate constant unary ops */
818 					zval result;
819 
820 optimize_const_unary_op:
821 					if (zend_optimizer_eval_unary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
822 						literal_dtor(&ZEND_OP1_LITERAL(opline));
823 						opline->opcode = ZEND_QM_ASSIGN;
824 						zend_optimizer_update_op1_const(op_array, opline, &result);
825 						++(*opt_count);
826 					}
827 				}
828 				break;
829 
830 			case ZEND_CAST:
831 				if (opline->op1_type == IS_CONST) {
832 					/* cast of constant operand */
833 					zval result;
834 
835 					if (zend_optimizer_eval_cast(&result, opline->extended_value, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
836 						literal_dtor(&ZEND_OP1_LITERAL(opline));
837 						opline->opcode = ZEND_QM_ASSIGN;
838 						opline->extended_value = 0;
839 						zend_optimizer_update_op1_const(op_array, opline, &result);
840 						++(*opt_count);
841 					}
842 				}
843 				break;
844 
845 			case ZEND_STRLEN:
846 				if (opline->op1_type == IS_CONST) {
847 					zval result;
848 
849 					if (zend_optimizer_eval_strlen(&result, &ZEND_OP1_LITERAL(opline)) == SUCCESS) {
850 						literal_dtor(&ZEND_OP1_LITERAL(opline));
851 						opline->opcode = ZEND_QM_ASSIGN;
852 						zend_optimizer_update_op1_const(op_array, opline, &result);
853 						++(*opt_count);
854 					}
855 				}
856 				break;
857 
858 			case ZEND_RETURN:
859 			case ZEND_EXIT:
860 				if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
861 					src = VAR_SOURCE(opline->op1);
862 					if (src && src->opcode == ZEND_QM_ASSIGN) {
863 						zend_op *op = src + 1;
864 						zend_bool optimize = 1;
865 
866 						while (op < opline) {
867 							if ((op->op1_type == opline->op1_type
868 							  && op->op1.var == opline->op1.var)
869 							 || (op->op2_type == opline->op1_type
870 							  && op->op2.var == opline->op1.var)) {
871 								optimize = 0;
872 								break;
873 							}
874 							op++;
875 						}
876 
877 						if (optimize) {
878 							/* T = QM_ASSIGN(X), RETURN(T) to NOP, RETURN(X) */
879 							VAR_SOURCE(opline->op1) = NULL;
880 							COPY_NODE(opline->op1, src->op1);
881 							MAKE_NOP(src);
882 							++(*opt_count);
883 						}
884 					}
885 				}
886 				break;
887 
888 			case ZEND_QM_ASSIGN:
889 				if (opline->op1_type == opline->result_type &&
890 				    opline->op1.var == opline->result.var) {
891 					/* strip T = QM_ASSIGN(T) */
892 					MAKE_NOP(opline);
893 					++(*opt_count);
894 				}
895 				break;
896 		}
897 
898 		/* get variable source */
899 		if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
900 			SET_VAR_SOURCE(opline);
901 		}
902 		opline++;
903 	}
904 }
905 
906 /* Rebuild plain (optimized) op_array from CFG */
assemble_code_blocks(zend_cfg * cfg,zend_op_array * op_array,zend_optimizer_ctx * ctx)907 static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_optimizer_ctx *ctx)
908 {
909 	zend_basic_block *blocks = cfg->blocks;
910 	zend_basic_block *end = blocks + cfg->blocks_count;
911 	zend_basic_block *b;
912 	zend_op *new_opcodes;
913 	zend_op *opline;
914 	uint32_t len = 0;
915 	int n;
916 
917 	for (b = blocks; b < end; b++) {
918 		if (b->len == 0) {
919 			continue;
920 		}
921 		if (b->flags & ZEND_BB_REACHABLE) {
922 			opline = op_array->opcodes + b->start + b->len - 1;
923 			if (opline->opcode == ZEND_JMP) {
924 				zend_basic_block *next = b + 1;
925 
926 				while (next < end && !(next->flags & ZEND_BB_REACHABLE)) {
927 					next++;
928 				}
929 				if (next < end && next == blocks + b->successors[0]) {
930 					/* JMP to the next block - strip it */
931 					MAKE_NOP(opline);
932 					b->len--;
933 				}
934 			} else if (b->len == 1 && opline->opcode == ZEND_NOP) {
935 				/* skip empty block */
936 				b->len--;
937 			}
938 			len += b->len;
939 		} else {
940 			/* this block will not be used, delete all constants there */
941 			zend_op *op = op_array->opcodes + b->start;
942 			zend_op *end = op + b->len;
943 			for (; op < end; op++) {
944 				if (op->op1_type == IS_CONST) {
945 					literal_dtor(&ZEND_OP1_LITERAL(op));
946 				}
947 				if (op->op2_type == IS_CONST) {
948 					literal_dtor(&ZEND_OP2_LITERAL(op));
949 				}
950 			}
951 		}
952 	}
953 
954 	new_opcodes = emalloc(len * sizeof(zend_op));
955 	opline = new_opcodes;
956 
957 	/* Copy code of reachable blocks into a single buffer */
958 	for (b = blocks; b < end; b++) {
959 		if (b->flags & ZEND_BB_REACHABLE) {
960 			memcpy(opline, op_array->opcodes + b->start, b->len * sizeof(zend_op));
961 			b->start = opline - new_opcodes;
962 			opline += b->len;
963 		}
964 	}
965 
966 	/* adjust jump targets */
967 	efree(op_array->opcodes);
968 	op_array->opcodes = new_opcodes;
969 	op_array->last = len;
970 
971 	for (b = blocks; b < end; b++) {
972 		if (!(b->flags & ZEND_BB_REACHABLE) || b->len == 0) {
973 			continue;
974 		}
975 		opline = op_array->opcodes + b->start + b->len - 1;
976 		switch (opline->opcode) {
977 			case ZEND_FAST_CALL:
978 			case ZEND_JMP:
979 				ZEND_SET_OP_JMP_ADDR(opline, opline->op1, new_opcodes + blocks[b->successors[0]].start);
980 				break;
981 			case ZEND_JMPZNZ:
982 				opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[1]].start);
983 				/* break missing intentionally */
984 			case ZEND_JMPZ:
985 			case ZEND_JMPNZ:
986 			case ZEND_JMPZ_EX:
987 			case ZEND_JMPNZ_EX:
988 			case ZEND_FE_RESET_R:
989 			case ZEND_FE_RESET_RW:
990 			case ZEND_JMP_SET:
991 			case ZEND_COALESCE:
992 			case ZEND_ASSERT_CHECK:
993 				ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
994 				break;
995 			case ZEND_CATCH:
996 				if (!(opline->extended_value & ZEND_LAST_CATCH)) {
997 					ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
998 				}
999 				break;
1000 			case ZEND_DECLARE_ANON_CLASS:
1001 			case ZEND_DECLARE_ANON_INHERITED_CLASS:
1002 			case ZEND_FE_FETCH_R:
1003 			case ZEND_FE_FETCH_RW:
1004 				opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[0]].start);
1005 				break;
1006 			case ZEND_SWITCH_LONG:
1007 			case ZEND_SWITCH_STRING:
1008 			{
1009 				HashTable *jumptable = Z_ARRVAL(ZEND_OP2_LITERAL(opline));
1010 				zval *zv;
1011 				uint32_t s = 0;
1012 				ZEND_ASSERT(b->successors_count == 2 + zend_hash_num_elements(jumptable));
1013 
1014 				ZEND_HASH_FOREACH_VAL(jumptable, zv) {
1015 					Z_LVAL_P(zv) = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[s++]].start);
1016 				} ZEND_HASH_FOREACH_END();
1017 				opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[s++]].start);
1018 				break;
1019 			}
1020 		}
1021 	}
1022 
1023 	/* adjust exception jump targets & remove unused try_catch_array entries */
1024 	if (op_array->last_try_catch) {
1025 		int i, j;
1026 		uint32_t *map;
1027 		ALLOCA_FLAG(use_heap);
1028 
1029 		map = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last_try_catch, use_heap);
1030 		for (i = 0, j = 0; i< op_array->last_try_catch; i++) {
1031 			if (blocks[cfg->map[op_array->try_catch_array[i].try_op]].flags & ZEND_BB_REACHABLE) {
1032 				map[i] = j;
1033 				op_array->try_catch_array[j].try_op = blocks[cfg->map[op_array->try_catch_array[i].try_op]].start;
1034 				if (op_array->try_catch_array[i].catch_op) {
1035 					op_array->try_catch_array[j].catch_op = blocks[cfg->map[op_array->try_catch_array[i].catch_op]].start;
1036 				} else {
1037 					op_array->try_catch_array[j].catch_op =  0;
1038 				}
1039 				if (op_array->try_catch_array[i].finally_op) {
1040 					op_array->try_catch_array[j].finally_op = blocks[cfg->map[op_array->try_catch_array[i].finally_op]].start;
1041 				} else {
1042 					op_array->try_catch_array[j].finally_op =  0;
1043 				}
1044 				if (!op_array->try_catch_array[i].finally_end) {
1045 					op_array->try_catch_array[j].finally_end = 0;
1046 				} else {
1047 					op_array->try_catch_array[j].finally_end = blocks[cfg->map[op_array->try_catch_array[i].finally_end]].start;
1048 				}
1049 				j++;
1050 			}
1051 		}
1052 		if (i != j) {
1053 			op_array->last_try_catch = j;
1054 			if (j == 0) {
1055 				efree(op_array->try_catch_array);
1056 				op_array->try_catch_array = NULL;
1057 			}
1058 
1059 			if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
1060 				zend_op *opline = new_opcodes;
1061 				zend_op *end = opline + len;
1062 				while (opline < end) {
1063 					if (opline->opcode == ZEND_FAST_RET &&
1064 					    opline->op2.num != (uint32_t)-1 &&
1065 					    opline->op2.num < (uint32_t)j) {
1066 						opline->op2.num = map[opline->op2.num];
1067 					}
1068 					opline++;
1069 				}
1070 			}
1071 		}
1072 		free_alloca(map, use_heap);
1073 	}
1074 
1075 	/* adjust loop jump targets & remove unused live range entries */
1076 	if (op_array->last_live_range) {
1077 		int i, j;
1078 
1079 		for (i = 0, j = 0; i < op_array->last_live_range; i++) {
1080 			if (op_array->live_range[i].var == (uint32_t)-1) {
1081 				/* this live range already removed */
1082 				continue;
1083 			}
1084 			if (!(blocks[cfg->map[op_array->live_range[i].start]].flags & ZEND_BB_REACHABLE)) {
1085 				ZEND_ASSERT(!(blocks[cfg->map[op_array->live_range[i].end]].flags & ZEND_BB_REACHABLE));
1086 			} else {
1087 				uint32_t start_op = blocks[cfg->map[op_array->live_range[i].start]].start;
1088 				uint32_t end_op = blocks[cfg->map[op_array->live_range[i].end]].start;
1089 
1090 				if (start_op == end_op) {
1091 					/* skip empty live range */
1092 					continue;
1093 				}
1094 				op_array->live_range[i].start = start_op;
1095 				op_array->live_range[i].end = end_op;
1096 				if (i != j) {
1097 					op_array->live_range[j]  = op_array->live_range[i];
1098 				}
1099 				j++;
1100 			}
1101 		}
1102 
1103 		if (i != j) {
1104 			op_array->last_live_range = j;
1105 			if (j == 0) {
1106 				efree(op_array->live_range);
1107 				op_array->live_range = NULL;
1108 			}
1109 		}
1110 	}
1111 
1112 	/* adjust early binding list */
1113 	if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) {
1114 		ZEND_ASSERT(op_array == &ctx->script->main_op_array);
1115 		ctx->script->first_early_binding_opline =
1116 			zend_build_delayed_early_binding_list(op_array);
1117 	}
1118 
1119 	/* rebuild map (just for printing) */
1120 	memset(cfg->map, -1, sizeof(int) * op_array->last);
1121 	for (n = 0; n < cfg->blocks_count; n++) {
1122 		if (cfg->blocks[n].flags & ZEND_BB_REACHABLE) {
1123 			cfg->map[cfg->blocks[n].start] = n;
1124 		}
1125 	}
1126 }
1127 
zend_jmp_optimization(zend_basic_block * block,zend_op_array * op_array,zend_cfg * cfg,zend_uchar * same_t,uint32_t * opt_count)1128 static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_array, zend_cfg *cfg, zend_uchar *same_t, uint32_t *opt_count)
1129 {
1130 	/* last_op is the last opcode of the current block */
1131 	zend_basic_block *blocks = cfg->blocks;
1132 	zend_op *last_op;
1133 
1134 	if (block->len == 0) {
1135 		return;
1136 	}
1137 
1138 	last_op = op_array->opcodes + block->start + block->len - 1;
1139 	switch (last_op->opcode) {
1140 		case ZEND_JMP:
1141 			{
1142 				zend_basic_block *target_block = blocks + block->successors[0];
1143 				zend_op *target = op_array->opcodes + target_block->start;
1144 				int next = (block - blocks) + 1;
1145 
1146 				while (next < cfg->blocks_count && !(blocks[next].flags & ZEND_BB_REACHABLE)) {
1147 					/* find used one */
1148 					next++;
1149 				}
1150 
1151 				/* JMP(next) -> NOP */
1152 				if (block->successors[0] == next) {
1153 					MAKE_NOP(last_op);
1154 					++(*opt_count);
1155 					block->len--;
1156 					break;
1157 				}
1158 
1159 				if (target->opcode == ZEND_JMP &&
1160 					block->successors[0] != target_block->successors[0] &&
1161 					!(target_block->flags & ZEND_BB_PROTECTED)) {
1162 					/* JMP L, L: JMP L1 -> JMP L1 */
1163 					*last_op = *target;
1164 					DEL_SOURCE(block, block->successors[0]);
1165 					block->successors[0] = target_block->successors[0];
1166 					ADD_SOURCE(block, block->successors[0]);
1167 					++(*opt_count);
1168 				} else if (target->opcode == ZEND_JMPZNZ &&
1169 				           !(target_block->flags & ZEND_BB_PROTECTED)) {
1170 					/* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ L1,L2 */
1171 					*last_op = *target;
1172 					if (last_op->op1_type == IS_CONST) {
1173 						zval zv;
1174 						ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(last_op));
1175 						last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
1176 					}
1177 					DEL_SOURCE(block, block->successors[0]);
1178 					block->successors_count = 2;
1179 					block->successors[0] = target_block->successors[0];
1180 					block->successors[1] = target_block->successors[1];
1181 					ADD_SOURCE(block, block->successors[0]);
1182 					ADD_SOURCE(block, block->successors[1]);
1183 					++(*opt_count);
1184 				} else if ((target->opcode == ZEND_RETURN ||
1185 				            target->opcode == ZEND_RETURN_BY_REF ||
1186 				            target->opcode == ZEND_EXIT) &&
1187 				           !(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
1188 					/* JMP L, L: RETURN to immediate RETURN */
1189 					*last_op = *target;
1190 					if (last_op->op1_type == IS_CONST) {
1191 						zval zv;
1192 						ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(last_op));
1193 						last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
1194 					}
1195 					DEL_SOURCE(block, block->successors[0]);
1196 					block->successors_count = 0;
1197 					++(*opt_count);
1198 #if 0
1199 				/* Temporarily disabled - see bug #0025274 */
1200 				} else if (0&& block->op1_to != block &&
1201 			           block->op1_to != blocks &&
1202 						   op_array->last_try_catch == 0 &&
1203 				           target->opcode != ZEND_FREE) {
1204 				    /* Block Reordering (saves one JMP on each "for" loop iteration)
1205 				     * It is disabled for some cases (ZEND_FREE)
1206 				     * which may break register allocation.
1207             	     */
1208 					zend_bool can_reorder = 0;
1209 					zend_block_source *cs = block->op1_to->sources;
1210 
1211 					/* the "target" block doesn't had any followed block */
1212 					while(cs) {
1213 						if (cs->from->follow_to == block->op1_to) {
1214 							can_reorder = 0;
1215 							break;
1216 						}
1217 						cs = cs->next;
1218 					}
1219 					if (can_reorder) {
1220 						next = block->op1_to;
1221 						/* the "target" block is not followed by current "block" */
1222 						while (next->follow_to != NULL) {
1223 							if (next->follow_to == block) {
1224 								can_reorder = 0;
1225 								break;
1226 							}
1227 							next = next->follow_to;
1228 						}
1229 						if (can_reorder) {
1230 							zend_basic_block *prev = blocks;
1231 
1232 							while (prev->next != block->op1_to) {
1233 								prev = prev->next;
1234 							}
1235 							prev->next = next->next;
1236 							next->next = block->next;
1237 							block->next = block->op1_to;
1238 
1239 							block->follow_to = block->op1_to;
1240 							block->op1_to = NULL;
1241 							MAKE_NOP(last_op);
1242 							block->len--;
1243 							if(block->len == 0) {
1244 								/* this block is nothing but NOP now */
1245 								delete_code_block(block, ctx);
1246 							}
1247 							break;
1248 						}
1249 					}
1250 #endif
1251 				}
1252 			}
1253 			break;
1254 
1255 		case ZEND_JMPZ:
1256 		case ZEND_JMPNZ:
1257 			/* constant conditional JMPs */
1258 			if (last_op->op1_type == IS_CONST) {
1259 				int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
1260 
1261 				if (last_op->opcode == ZEND_JMPZ) {
1262 					should_jmp = !should_jmp;
1263 				}
1264 				literal_dtor(&ZEND_OP1_LITERAL(last_op));
1265 				last_op->op1_type = IS_UNUSED;
1266 				if (should_jmp) {
1267 					/* JMPNZ(true) -> JMP */
1268 					last_op->opcode = ZEND_JMP;
1269 					DEL_SOURCE(block, block->successors[1]);
1270 					block->successors_count = 1;
1271 				} else {
1272 					/* JMPNZ(false) -> NOP */
1273 					MAKE_NOP(last_op);
1274 					DEL_SOURCE(block, block->successors[0]);
1275 					block->successors_count = 1;
1276 					block->successors[0] = block->successors[1];
1277 				}
1278 				++(*opt_count);
1279 				break;
1280 			}
1281 
1282 			if (block->successors[0] == block->successors[1]) {
1283 				/* L: JMP[N]Z(X, L+1) -> NOP or FREE(X) */
1284 
1285 				if (last_op->op1_type == IS_CV) {
1286 					last_op->opcode = ZEND_CHECK_VAR;
1287 					last_op->op2.num = 0;
1288 				} else if (last_op->op1_type & (IS_VAR|IS_TMP_VAR)) {
1289 					last_op->opcode = ZEND_FREE;
1290 					last_op->op2.num = 0;
1291 				} else {
1292 					MAKE_NOP(last_op);
1293 				}
1294 				block->successors_count = 1;
1295 				++(*opt_count);
1296 				break;
1297 			}
1298 
1299 			if (1) {
1300 				zend_uchar same_type = last_op->op1_type;
1301 				uint32_t same_var = VAR_NUM_EX(last_op->op1);
1302 				zend_op *target;
1303 				zend_op *target_end;
1304 				zend_basic_block *target_block = blocks + block->successors[0];
1305 
1306 next_target:
1307 				target = op_array->opcodes + target_block->start;
1308 				target_end = target + target_block->len;
1309 				while (target < target_end && target->opcode == ZEND_NOP) {
1310 					target++;
1311 				}
1312 
1313 				/* next block is only NOP's */
1314 				if (target == target_end) {
1315 					target_block = blocks + target_block->successors[0];
1316 					++(*opt_count);
1317 					goto next_target;
1318 				} else if (target->opcode == INV_COND(last_op->opcode) &&
1319 					/* JMPZ(X, L), L: JMPNZ(X, L2) -> JMPZ(X, L+1) */
1320 				   (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
1321 				   same_type == target->op1_type &&
1322 				   same_var == VAR_NUM_EX(target->op1) &&
1323 				   !(target_block->flags & ZEND_BB_PROTECTED)
1324 				   ) {
1325 					DEL_SOURCE(block, block->successors[0]);
1326 					block->successors[0] = target_block->successors[1];
1327 					ADD_SOURCE(block, block->successors[0]);
1328 					++(*opt_count);
1329 				} else if (target->opcode == INV_COND_EX(last_op->opcode) &&
1330 							(target->op1_type & (IS_TMP_VAR|IS_CV)) &&
1331 				    		same_type == target->op1_type &&
1332 				    		same_var == VAR_NUM_EX(target->op1) &&
1333 							!(target_block->flags & ZEND_BB_PROTECTED)) {
1334 					/* JMPZ(X, L), L: T = JMPNZ_EX(X, L2) -> T = JMPZ_EX(X, L+1) */
1335 					last_op->opcode += 3;
1336 					COPY_NODE(last_op->result, target->result);
1337 					DEL_SOURCE(block, block->successors[0]);
1338 					block->successors[0] = target_block->successors[1];
1339 					ADD_SOURCE(block, block->successors[0]);
1340 					++(*opt_count);
1341 				} else if (target->opcode == last_op->opcode &&
1342 						   (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
1343 						   same_type == target->op1_type &&
1344 						   same_var == VAR_NUM_EX(target->op1) &&
1345 						   !(target_block->flags & ZEND_BB_PROTECTED)) {
1346 					/* JMPZ(X, L), L: JMPZ(X, L2) -> JMPZ(X, L2) */
1347 					DEL_SOURCE(block, block->successors[0]);
1348 					block->successors[0] = target_block->successors[0];
1349 					ADD_SOURCE(block, block->successors[0]);
1350 					++(*opt_count);
1351 				} else if (target->opcode == ZEND_JMP &&
1352 				           !(target_block->flags & ZEND_BB_PROTECTED)) {
1353 					/* JMPZ(X, L), L: JMP(L2) -> JMPZ(X, L2) */
1354 					DEL_SOURCE(block, block->successors[0]);
1355 					block->successors[0] = target_block->successors[0];
1356 					ADD_SOURCE(block, block->successors[0]);
1357 					++(*opt_count);
1358 				} else if (target->opcode == ZEND_JMPZNZ &&
1359 				           (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
1360 				           same_type == target->op1_type &&
1361 				           same_var == VAR_NUM_EX(target->op1) &&
1362 				           !(target_block->flags & ZEND_BB_PROTECTED)) {
1363 					/* JMPZ(X, L), L: JMPZNZ(X, L2, L3) -> JMPZ(X, L2) */
1364 					DEL_SOURCE(block, block->successors[0]);
1365 					if (last_op->opcode == ZEND_JMPZ) {
1366 						block->successors[0] = target_block->successors[0];
1367 					} else {
1368 						block->successors[0] = target_block->successors[1];
1369 					}
1370 					ADD_SOURCE(block, block->successors[0]);
1371 					++(*opt_count);
1372 				}
1373 			}
1374 
1375 			if (last_op->opcode == ZEND_JMPZ || last_op->opcode == ZEND_JMPNZ) {
1376 				zend_op *target;
1377 				zend_op *target_end;
1378 				zend_basic_block *target_block;
1379 
1380 				while (1) {
1381 					target_block = blocks + block->successors[1];
1382 					target = op_array->opcodes + target_block->start;
1383 					target_end = op_array->opcodes + target_block->start + 1;
1384 					while (target < target_end && target->opcode == ZEND_NOP) {
1385 						target++;
1386 					}
1387 
1388 					/* next block is only NOP's */
1389 					if (target == target_end && !(target_block->flags & ZEND_BB_PROTECTED)) {
1390 						DEL_SOURCE(block, block->successors[1]);
1391 						block->successors[1] = target_block->successors[0];
1392 						ADD_SOURCE(block, block->successors[1]);
1393 						++(*opt_count);
1394 					} else {
1395 						break;
1396 					}
1397 				}
1398 				/* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
1399 				if (target->opcode == ZEND_JMP &&
1400 					!(target_block->flags & ZEND_BB_PROTECTED)) {
1401 					DEL_SOURCE(block, block->successors[1]);
1402 					if (last_op->opcode == ZEND_JMPZ) {
1403 						block->successors[1] = target_block->successors[0];
1404 						ADD_SOURCE(block, block->successors[1]);
1405 					} else {
1406 						block->successors[1] = block->successors[0];
1407 						block->successors[0] = target_block->successors[0];
1408 						ADD_SOURCE(block, block->successors[0]);
1409 					}
1410 					last_op->opcode = ZEND_JMPZNZ;
1411 					++(*opt_count);
1412 				}
1413 			}
1414 			break;
1415 
1416 		case ZEND_JMPNZ_EX:
1417 		case ZEND_JMPZ_EX:
1418 			/* constant conditional JMPs */
1419 			if (last_op->op1_type == IS_CONST) {
1420 				int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
1421 
1422 				if (last_op->opcode == ZEND_JMPZ_EX) {
1423 					should_jmp = !should_jmp;
1424 				}
1425 				if (!should_jmp) {
1426 					/* T = JMPZ_EX(true,L)   -> T = QM_ASSIGN(true)
1427 					 * T = JMPNZ_EX(false,L) -> T = QM_ASSIGN(false)
1428 					 */
1429 					last_op->opcode = ZEND_QM_ASSIGN;
1430 					SET_UNUSED(last_op->op2);
1431 					DEL_SOURCE(block, block->successors[0]);
1432 					block->successors_count = 1;
1433 					block->successors[0] = block->successors[1];
1434 					++(*opt_count);
1435 				}
1436 				break;
1437 			}
1438 
1439 			if (1) {
1440 				zend_op *target, *target_end;
1441 				zend_basic_block *target_block;
1442 				int var_num = op_array->last_var + op_array->T;
1443 
1444 				if (var_num <= 0) {
1445    					return;
1446 				}
1447 				memset(same_t, 0, var_num);
1448 				same_t[VAR_NUM_EX(last_op->op1)] |= last_op->op1_type;
1449 				same_t[VAR_NUM_EX(last_op->result)] |= last_op->result_type;
1450 				target_block = blocks + block->successors[0];
1451 next_target_ex:
1452 				target = op_array->opcodes + target_block->start;
1453 				target_end = target + target_block->len;
1454 				while (target < target_end && target->opcode == ZEND_NOP) {
1455 					target++;
1456 				}
1457  				/* next block is only NOP's */
1458 				if (target == target_end) {
1459 					target_block = blocks + target_block->successors[0];
1460 					++(*opt_count);
1461 					goto next_target_ex;
1462 				} else if (target->opcode == last_op->opcode-3 &&
1463 						   (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
1464 						   (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
1465 						   !(target_block->flags & ZEND_BB_PROTECTED)) {
1466 					/* T = JMPZ_EX(X, L1), L1: JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
1467 					DEL_SOURCE(block, block->successors[0]);
1468 					block->successors[0] = target_block->successors[0];
1469 					ADD_SOURCE(block, block->successors[0]);
1470 					++(*opt_count);
1471 				} else if (target->opcode == INV_EX_COND(last_op->opcode) &&
1472 					   	   (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
1473 						   (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
1474 						   !(target_block->flags & ZEND_BB_PROTECTED)) {
1475 					/* T = JMPZ_EX(X, L1), L1: JMPNZ({X|T1}, L2) -> T = JMPZ_EX(X, L1+1) */
1476 					DEL_SOURCE(block, block->successors[0]);
1477 					block->successors[0] = target_block->successors[1];
1478 					ADD_SOURCE(block, block->successors[0]);
1479 					++(*opt_count);
1480 				} else if (target->opcode == INV_EX_COND_EX(last_op->opcode) &&
1481 					       (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
1482 						   (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
1483 						   (same_t[VAR_NUM_EX(target->result)] & target->result_type) != 0 &&
1484 						   !(target_block->flags & ZEND_BB_PROTECTED)) {
1485 					/* T = JMPZ_EX(X, L1), L1: T = JMPNZ_EX(T, L2) -> T = JMPZ_EX(X, L1+1) */
1486 					DEL_SOURCE(block, block->successors[0]);
1487 					block->successors[0] = target_block->successors[1];
1488 					ADD_SOURCE(block, block->successors[0]);
1489 					++(*opt_count);
1490 				} else if (target->opcode == last_op->opcode &&
1491 						   (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
1492 						   (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
1493 						   (same_t[VAR_NUM_EX(target->result)] & target->result_type) != 0 &&
1494 						   !(target_block->flags & ZEND_BB_PROTECTED)) {
1495 					/* T = JMPZ_EX(X, L1), L1: T = JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
1496 					DEL_SOURCE(block, block->successors[0]);
1497 					block->successors[0] = target_block->successors[0];
1498 					ADD_SOURCE(block, block->successors[0]);
1499 					++(*opt_count);
1500 				} else if (target->opcode == ZEND_JMP &&
1501 						   !(target_block->flags & ZEND_BB_PROTECTED)) {
1502 					/* T = JMPZ_EX(X, L), L: JMP(L2) -> T = JMPZ(X, L2) */
1503 					DEL_SOURCE(block, block->successors[0]);
1504 					block->successors[0] = target_block->successors[0];
1505 					ADD_SOURCE(block, block->successors[0]);
1506 					++(*opt_count);
1507 				} else if (target->opcode == ZEND_JMPZNZ &&
1508 						   (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
1509 						   (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
1510 						   !(target_block->flags & ZEND_BB_PROTECTED)) {
1511 					/* T = JMPZ_EX(X, L), L: JMPZNZ({X|T}, L2, L3) -> T = JMPZ_EX(X, L2) */
1512 					DEL_SOURCE(block, block->successors[0]);
1513 					if (last_op->opcode == ZEND_JMPZ_EX) {
1514 						block->successors[0] = target_block->successors[0];
1515 					} else {
1516 						block->successors[0] = target_block->successors[1];
1517 					}
1518 					ADD_SOURCE(block, block->successors[0]);
1519 					++(*opt_count);
1520 				}
1521 			}
1522 			break;
1523 
1524 		case ZEND_JMPZNZ: {
1525 			int next = (block - blocks) + 1;
1526 
1527 			while (next < cfg->blocks_count && !(blocks[next].flags & ZEND_BB_REACHABLE)) {
1528 				/* find first accessed one */
1529 				next++;
1530 			}
1531 
1532 			if (last_op->op1_type == IS_CONST) {
1533 				if (!zend_is_true(&ZEND_OP1_LITERAL(last_op))) {
1534 					/* JMPZNZ(false,L1,L2) -> JMP(L1) */
1535 					literal_dtor(&ZEND_OP1_LITERAL(last_op));
1536 					last_op->opcode = ZEND_JMP;
1537 					SET_UNUSED(last_op->op1);
1538 					SET_UNUSED(last_op->op2);
1539 					DEL_SOURCE(block, block->successors[1]);
1540 					block->successors_count = 1;
1541 				} else {
1542 					/* JMPZNZ(true,L1,L2) -> JMP(L2) */
1543 					literal_dtor(&ZEND_OP1_LITERAL(last_op));
1544 					last_op->opcode = ZEND_JMP;
1545 					SET_UNUSED(last_op->op1);
1546 					SET_UNUSED(last_op->op2);
1547 					DEL_SOURCE(block, block->successors[0]);
1548 					block->successors_count = 1;
1549 					block->successors[0] = block->successors[1];
1550 				}
1551 				++(*opt_count);
1552 			} else if (block->successors[0] == block->successors[1]) {
1553 				/* both goto the same one - it's JMP */
1554 				if (!(last_op->op1_type & (IS_VAR|IS_TMP_VAR))) {
1555 					/* JMPZNZ(?,L,L) -> JMP(L) */
1556 					last_op->opcode = ZEND_JMP;
1557 					SET_UNUSED(last_op->op1);
1558 					SET_UNUSED(last_op->op2);
1559 					block->successors_count = 1;
1560 					++(*opt_count);
1561 				}
1562 			} else if (block->successors[0] == next) {
1563 				/* jumping to next on Z - can follow to it and jump only on NZ */
1564 				/* JMPZNZ(X,L1,L2) L1: -> JMPNZ(X,L2) */
1565 				last_op->opcode = ZEND_JMPNZ;
1566 				block->successors[0] = block->successors[1];
1567 				block->successors[1] = next;
1568 				++(*opt_count);
1569 				/* no need to add source */
1570 			} else if (block->successors[1] == next) {
1571 				/* jumping to next on NZ - can follow to it and jump only on Z */
1572 				/* JMPZNZ(X,L1,L2) L2: -> JMPZ(X,L1) */
1573 				last_op->opcode = ZEND_JMPZ;
1574 				++(*opt_count);
1575 				/* no need to add source */
1576 			}
1577 
1578 			if (last_op->opcode == ZEND_JMPZNZ) {
1579 				zend_uchar same_type = last_op->op1_type;
1580 				zend_uchar same_var = VAR_NUM_EX(last_op->op1);
1581 				zend_op *target;
1582 				zend_op *target_end;
1583 				zend_basic_block *target_block = blocks + block->successors[0];
1584 
1585 next_target_znz:
1586 				target = op_array->opcodes + target_block->start;
1587 				target_end = target + target_block->len;
1588 				while (target < target_end && target->opcode == ZEND_NOP) {
1589 					target++;
1590 				}
1591 				/* next block is only NOP's */
1592 				if (target == target_end) {
1593 					target_block = blocks + target_block->successors[0];
1594 					++(*opt_count);
1595 					goto next_target_znz;
1596 				} else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
1597 						   (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
1598 						   same_type == target->op1_type &&
1599 						   same_var == VAR_NUM_EX(target->op1) &&
1600 						   !(target_block->flags & ZEND_BB_PROTECTED)) {
1601 				    /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
1602 					DEL_SOURCE(block, block->successors[0]);
1603 					block->successors[0] = target_block->successors[0];
1604 					ADD_SOURCE(block, block->successors[0]);
1605 					++(*opt_count);
1606 				} else if (target->opcode == ZEND_JMPNZ &&
1607 						   (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
1608 						   same_type == target->op1_type &&
1609 						   same_var == VAR_NUM_EX(target->op1) &&
1610 						   !(target_block->flags & ZEND_BB_PROTECTED)) {
1611                     /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
1612 					DEL_SOURCE(block, block->successors[0]);
1613 					block->successors[0] = target_block->successors[1];
1614 					ADD_SOURCE(block, block->successors[0]);
1615 					++(*opt_count);
1616 				} else if (target->opcode == ZEND_JMP &&
1617 					       !(target_block->flags & ZEND_BB_PROTECTED)) {
1618                     /* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
1619 					DEL_SOURCE(block, block->successors[0]);
1620 					block->successors[0] = target_block->successors[0];
1621 					ADD_SOURCE(block, block->successors[0]);
1622 					++(*opt_count);
1623 				}
1624 			}
1625 			break;
1626 		}
1627 	}
1628 }
1629 
1630 /* Global data dependencies */
1631 
1632 /* Find a set of variables which are used outside of the block where they are
1633  * defined. We won't apply some optimization patterns for such variables. */
zend_t_usage(zend_cfg * cfg,zend_op_array * op_array,zend_bitset used_ext,zend_optimizer_ctx * ctx)1634 static void zend_t_usage(zend_cfg *cfg, zend_op_array *op_array, zend_bitset used_ext, zend_optimizer_ctx *ctx)
1635 {
1636 	int n;
1637 	zend_basic_block *block, *next_block;
1638 	uint32_t var_num;
1639 	uint32_t bitset_len;
1640 	zend_bitset usage;
1641 	zend_bitset defined_here;
1642 	void *checkpoint;
1643 	zend_op *opline, *end;
1644 
1645 
1646 	if (op_array->T == 0) {
1647 		/* shortcut - if no Ts, nothing to do */
1648 		return;
1649 	}
1650 
1651 	checkpoint = zend_arena_checkpoint(ctx->arena);
1652 	bitset_len = zend_bitset_len(op_array->last_var + op_array->T);
1653 	defined_here = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
1654 
1655 	zend_bitset_clear(defined_here, bitset_len);
1656 	for (n = 1; n < cfg->blocks_count; n++) {
1657 		block = cfg->blocks + n;
1658 
1659 		if (!(block->flags & ZEND_BB_REACHABLE)) {
1660 			continue;
1661 		}
1662 
1663 		opline = op_array->opcodes + block->start;
1664 		end = opline + block->len;
1665 		if (!(block->flags & ZEND_BB_FOLLOW) ||
1666 		    (block->flags & ZEND_BB_TARGET)) {
1667 			/* Skip continuation of "extended" BB */
1668 			zend_bitset_clear(defined_here, bitset_len);
1669 		}
1670 
1671 		while (opline<end) {
1672 			if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
1673 				var_num = VAR_NUM(opline->op1.var);
1674 				if (!zend_bitset_in(defined_here, var_num)) {
1675 					zend_bitset_incl(used_ext, var_num);
1676 				}
1677 			}
1678 			if (opline->op2_type == IS_VAR) {
1679 				var_num = VAR_NUM(opline->op2.var);
1680 				if (opline->opcode == ZEND_FE_FETCH_R ||
1681 				    opline->opcode == ZEND_FE_FETCH_RW) {
1682 					/* these opcode use the op2 as result */
1683 					zend_bitset_incl(defined_here, var_num);
1684 				} else if (!zend_bitset_in(defined_here, var_num)) {
1685 					zend_bitset_incl(used_ext, var_num);
1686 				}
1687 			} else if (opline->op2_type == IS_TMP_VAR) {
1688 				var_num = VAR_NUM(opline->op2.var);
1689 				if (!zend_bitset_in(defined_here, var_num)) {
1690 					zend_bitset_incl(used_ext, var_num);
1691 				}
1692 			}
1693 
1694 			if (opline->result_type == IS_VAR) {
1695 				var_num = VAR_NUM(opline->result.var);
1696 				zend_bitset_incl(defined_here, var_num);
1697 			} else if (opline->result_type == IS_TMP_VAR) {
1698 				var_num = VAR_NUM(opline->result.var);
1699 				switch (opline->opcode) {
1700 					case ZEND_ADD_ARRAY_ELEMENT:
1701 					case ZEND_ROPE_ADD:
1702 						/* these opcodes use the result as argument */
1703 						if (!zend_bitset_in(defined_here, var_num)) {
1704 							zend_bitset_incl(used_ext, var_num);
1705 						}
1706 						break;
1707 					default :
1708 						zend_bitset_incl(defined_here, var_num);
1709 				}
1710 			}
1711 			opline++;
1712 		}
1713 	}
1714 
1715 	if (ctx->debug_level & ZEND_DUMP_BLOCK_PASS_VARS) {
1716 		int printed = 0;
1717 		uint32_t i;
1718 
1719 		for (i = op_array->last_var; i< op_array->T; i++) {
1720 			if (zend_bitset_in(used_ext, i)) {
1721 				if (!printed) {
1722 					fprintf(stderr, "NON-LOCAL-VARS: %d", i);
1723 					printed = 1;
1724 				} else {
1725 					fprintf(stderr, ", %d", i);
1726 				}
1727 			}
1728 		}
1729 		if (printed) {
1730 			fprintf(stderr, "\n");
1731 		}
1732 	}
1733 
1734 	usage = defined_here;
1735 	next_block = NULL;
1736 	for (n = cfg->blocks_count; n > 0;) {
1737 		block = cfg->blocks + (--n);
1738 
1739 		if (!(block->flags & ZEND_BB_REACHABLE) || block->len == 0) {
1740 			continue;
1741 		}
1742 
1743 		end = op_array->opcodes + block->start;
1744 		opline = end + block->len - 1;
1745 		if (!next_block ||
1746 		    !(next_block->flags & ZEND_BB_FOLLOW) ||
1747 		    (next_block->flags & ZEND_BB_TARGET)) {
1748 			/* Skip continuation of "extended" BB */
1749 			zend_bitset_copy(usage, used_ext, bitset_len);
1750 		} else if (block->successors_count > 1) {
1751 			zend_bitset_union(usage, used_ext, bitset_len);
1752 		}
1753 		next_block = block;
1754 
1755 		while (opline >= end) {
1756 			/* usage checks */
1757 			if (opline->result_type == IS_VAR) {
1758 				if (!zend_bitset_in(usage, VAR_NUM(opline->result.var))) {
1759 					switch (opline->opcode) {
1760 						case ZEND_ASSIGN_ADD:
1761 						case ZEND_ASSIGN_SUB:
1762 						case ZEND_ASSIGN_MUL:
1763 						case ZEND_ASSIGN_DIV:
1764 						case ZEND_ASSIGN_POW:
1765 						case ZEND_ASSIGN_MOD:
1766 						case ZEND_ASSIGN_SL:
1767 						case ZEND_ASSIGN_SR:
1768 						case ZEND_ASSIGN_CONCAT:
1769 						case ZEND_ASSIGN_BW_OR:
1770 						case ZEND_ASSIGN_BW_AND:
1771 						case ZEND_ASSIGN_BW_XOR:
1772 						case ZEND_PRE_INC:
1773 						case ZEND_PRE_DEC:
1774 						case ZEND_ASSIGN:
1775 						case ZEND_ASSIGN_REF:
1776 						case ZEND_DO_FCALL:
1777 						case ZEND_DO_ICALL:
1778 						case ZEND_DO_UCALL:
1779 						case ZEND_DO_FCALL_BY_NAME:
1780 							opline->result_type = IS_UNUSED;
1781 							break;
1782 					}
1783 				} else {
1784 					zend_bitset_excl(usage, VAR_NUM(opline->result.var));
1785 				}
1786 			} else if (opline->result_type == IS_TMP_VAR) {
1787 				if (!zend_bitset_in(usage, VAR_NUM(opline->result.var))) {
1788 					switch (opline->opcode) {
1789 						case ZEND_POST_INC:
1790 						case ZEND_POST_DEC:
1791 						case ZEND_POST_INC_OBJ:
1792 						case ZEND_POST_DEC_OBJ:
1793 							opline->opcode -= 2;
1794 							opline->result_type = IS_UNUSED;
1795 							break;
1796 						case ZEND_QM_ASSIGN:
1797 						case ZEND_BOOL:
1798 						case ZEND_BOOL_NOT:
1799 							if (opline->op1_type == IS_CV) {
1800 								opline->opcode = ZEND_CHECK_VAR;
1801 								SET_UNUSED(opline->result);
1802 							} else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
1803 								opline->opcode = ZEND_FREE;
1804 								SET_UNUSED(opline->result);
1805 							} else {
1806 								if (opline->op1_type == IS_CONST) {
1807 									literal_dtor(&ZEND_OP1_LITERAL(opline));
1808 								}
1809 								MAKE_NOP(opline);
1810 							}
1811 							break;
1812 						case ZEND_JMPZ_EX:
1813 						case ZEND_JMPNZ_EX:
1814 							opline->opcode -= 3;
1815 							SET_UNUSED(opline->result);
1816 							break;
1817 						case ZEND_ADD_ARRAY_ELEMENT:
1818 						case ZEND_ROPE_ADD:
1819 							zend_bitset_incl(usage, VAR_NUM(opline->result.var));
1820 							break;
1821 					}
1822 				} else {
1823 					switch (opline->opcode) {
1824 						case ZEND_ADD_ARRAY_ELEMENT:
1825 						case ZEND_ROPE_ADD:
1826 							break;
1827 						default:
1828 							zend_bitset_excl(usage, VAR_NUM(opline->result.var));
1829 							break;
1830 					}
1831 				}
1832 			}
1833 
1834 			if (opline->op2_type == IS_VAR) {
1835 				switch (opline->opcode) {
1836 					case ZEND_FE_FETCH_R:
1837 					case ZEND_FE_FETCH_RW:
1838 						zend_bitset_excl(usage, VAR_NUM(opline->op2.var));
1839 						break;
1840 					default:
1841 						zend_bitset_incl(usage, VAR_NUM(opline->op2.var));
1842 						break;
1843 				}
1844 			} else if (opline->op2_type == IS_TMP_VAR) {
1845 				zend_bitset_incl(usage, VAR_NUM(opline->op2.var));
1846 			}
1847 
1848 			if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
1849 				zend_bitset_incl(usage, VAR_NUM(opline->op1.var));
1850 			}
1851 
1852 			opline--;
1853 		}
1854 	}
1855 
1856 	zend_arena_release(&ctx->arena, checkpoint);
1857 }
1858 
zend_merge_blocks(zend_op_array * op_array,zend_cfg * cfg,uint32_t * opt_count)1859 static void zend_merge_blocks(zend_op_array *op_array, zend_cfg *cfg, uint32_t *opt_count)
1860 {
1861 	int i;
1862 	zend_basic_block *b, *bb;
1863 	zend_basic_block *prev = NULL;
1864 
1865 	for (i = 0; i < cfg->blocks_count; i++) {
1866 		b = cfg->blocks + i;
1867 		if (b->flags & ZEND_BB_REACHABLE) {
1868 			if ((b->flags & ZEND_BB_FOLLOW) &&
1869 			    !(b->flags & (ZEND_BB_TARGET | ZEND_BB_PROTECTED)) &&
1870 			    prev && prev->successors_count == 1 && prev->successors[0] == i)
1871 			{
1872 				zend_op *last_op = op_array->opcodes + prev->start + prev->len - 1;
1873 				if (prev->len != 0 && last_op->opcode == ZEND_JMP) {
1874 					MAKE_NOP(last_op);
1875 				}
1876 
1877 				for (bb = prev + 1; bb != b; bb++) {
1878 					zend_op *op = op_array->opcodes + bb->start;
1879 					zend_op *end = op + bb->len;
1880 					while (op < end) {
1881 						if (op->op1_type == IS_CONST) {
1882 							literal_dtor(&ZEND_OP1_LITERAL(op));
1883 						}
1884 						if (op->op2_type == IS_CONST) {
1885 							literal_dtor(&ZEND_OP2_LITERAL(op));
1886 						}
1887 						MAKE_NOP(op);
1888 						op++;
1889 					}
1890 					/* make block empty */
1891 					bb->len = 0;
1892 				}
1893 
1894 				/* re-link */
1895 				prev->flags |= (b->flags & ZEND_BB_EXIT);
1896 				prev->len = b->start + b->len - prev->start;
1897 				prev->successors_count = b->successors_count;
1898 				if (b->successors != b->successors_storage) {
1899 					prev->successors = b->successors;
1900 					b->successors = b->successors_storage;
1901 				} else {
1902 					memcpy(prev->successors, b->successors, b->successors_count * sizeof(int));
1903 				}
1904 
1905 				/* unlink & make block empty and unreachable */
1906 				b->flags = 0;
1907 				b->len = 0;
1908 				b->successors_count = 0;
1909 				++(*opt_count);
1910 			} else {
1911 				prev = b;
1912 			}
1913 		}
1914 	}
1915 }
1916 
1917 #define PASSES 3
1918 
zend_optimize_cfg(zend_op_array * op_array,zend_optimizer_ctx * ctx)1919 void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
1920 {
1921 	zend_cfg cfg;
1922 	zend_basic_block *blocks, *end, *b;
1923 	int pass;
1924 	uint32_t bitset_len;
1925 	zend_bitset usage;
1926 	void *checkpoint;
1927 	zend_op **Tsource;
1928 	zend_uchar *same_t;
1929 	uint32_t opt_count;
1930 
1931     /* Build CFG */
1932 	checkpoint = zend_arena_checkpoint(ctx->arena);
1933 	if (zend_build_cfg(&ctx->arena, op_array, ZEND_CFG_SPLIT_AT_LIVE_RANGES, &cfg) != SUCCESS) {
1934 		zend_arena_release(&ctx->arena, checkpoint);
1935 		return;
1936 	}
1937 
1938 	if (cfg.blocks_count * (op_array->last_var + op_array->T) > 64 * 1024 * 1024) {
1939 		zend_arena_release(&ctx->arena, checkpoint);
1940 		return;
1941 	}
1942 
1943 	if (ctx->debug_level & ZEND_DUMP_BEFORE_BLOCK_PASS) {
1944 		zend_dump_op_array(op_array, ZEND_DUMP_CFG, "before block pass", &cfg);
1945 	}
1946 
1947 	if (op_array->last_var || op_array->T) {
1948 		bitset_len = zend_bitset_len(op_array->last_var + op_array->T);
1949 		Tsource = zend_arena_calloc(&ctx->arena, op_array->last_var + op_array->T, sizeof(zend_op *));
1950 		same_t = zend_arena_alloc(&ctx->arena, op_array->last_var + op_array->T);
1951 		usage = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
1952 	} else {
1953 		bitset_len = 0;
1954 		Tsource = NULL;
1955 		same_t = NULL;
1956 		usage = NULL;
1957 	}
1958 	blocks = cfg.blocks;
1959 	end = blocks + cfg.blocks_count;
1960 	for (pass = 0; pass < PASSES; pass++) {
1961 		opt_count = 0;
1962 
1963 		/* Compute data dependencies */
1964 		zend_bitset_clear(usage, bitset_len);
1965 		zend_t_usage(&cfg, op_array, usage, ctx);
1966 
1967 		/* optimize each basic block separately */
1968 		for (b = blocks; b < end; b++) {
1969 			if (!(b->flags & ZEND_BB_REACHABLE)) {
1970 				continue;
1971 			}
1972 			/* we track data dependencies only insight a single basic block */
1973 			if (!(b->flags & ZEND_BB_FOLLOW) ||
1974 			    (b->flags & ZEND_BB_TARGET)) {
1975 				/* Skip continuation of "extended" BB */
1976 				memset(Tsource, 0, (op_array->last_var + op_array->T) * sizeof(zend_op *));
1977 			}
1978 			zend_optimize_block(b, op_array, usage, &cfg, Tsource, &opt_count);
1979 		}
1980 
1981 		/* Eliminate NOPs */
1982 		for (b = blocks; b < end; b++) {
1983 			if (b->flags & ZEND_BB_REACHABLE) {
1984 				strip_nops(op_array, b);
1985 			}
1986 		}
1987 
1988 		/* Jump optimization for each block */
1989 		for (b = blocks; b < end; b++) {
1990 			if (b->flags & ZEND_BB_REACHABLE) {
1991 				zend_jmp_optimization(b, op_array, &cfg, same_t, &opt_count);
1992 			}
1993 		}
1994 
1995 		/* Eliminate unreachable basic blocks */
1996 		zend_cfg_remark_reachable_blocks(op_array, &cfg);
1997 
1998 		/* Merge Blocks */
1999 		zend_merge_blocks(op_array, &cfg, &opt_count);
2000 
2001 		if (opt_count == 0) {
2002 			break;
2003 		}
2004 	}
2005 
2006 	zend_bitset_clear(usage, bitset_len);
2007 	zend_t_usage(&cfg, op_array, usage, ctx);
2008 	assemble_code_blocks(&cfg, op_array, ctx);
2009 
2010 	if (ctx->debug_level & ZEND_DUMP_AFTER_BLOCK_PASS) {
2011 		zend_dump_op_array(op_array, ZEND_DUMP_CFG | ZEND_DUMP_HIDE_UNREACHABLE, "after block pass", &cfg);
2012 	}
2013 
2014 	/* Destroy CFG */
2015 	zend_arena_release(&ctx->arena, checkpoint);
2016 }
2017