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