xref: /PHP-5.5/ext/opcache/Optimizer/nop_removal.c (revision 34d3202e)
1 /* pass 10:
2  * - remove NOPs
3  */
4 
nop_removal(zend_op_array * op_array)5 static void nop_removal(zend_op_array *op_array)
6 {
7 	zend_op *end, *opline;
8 	zend_uint new_count, i, shift;
9 	int j;
10 	zend_uint *shiftlist;
11 	ALLOCA_FLAG(use_heap);
12 
13 	shiftlist = (zend_uint *)DO_ALLOCA(sizeof(zend_uint) * op_array->last);
14 	i = new_count = shift = 0;
15 	end = op_array->opcodes + op_array->last;
16 	for (opline = op_array->opcodes; opline < end; opline++) {
17 
18 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
19 		/* GOTO target is unresolved yet. We can't optimize. */
20 		if (opline->opcode == ZEND_GOTO &&
21 			Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
22 			/* TODO: in general we can avoid this restriction */
23 			FREE_ALLOCA(shiftlist);
24 			return;
25 		}
26 #endif
27 
28 		/* Kill JMP-over-NOP-s */
29 		if (opline->opcode == ZEND_JMP && ZEND_OP1(opline).opline_num > i) {
30 			/* check if there are only NOPs under the branch */
31 			zend_op *target = op_array->opcodes + ZEND_OP1(opline).opline_num - 1;
32 
33 			while (target->opcode == ZEND_NOP) {
34 				target--;
35 			}
36 			if (target == opline) {
37 				/* only NOPs */
38 				opline->opcode = ZEND_NOP;
39 			}
40 		}
41 
42 		shiftlist[i++] = shift;
43 		if (opline->opcode == ZEND_NOP) {
44 			shift++;
45 		} else {
46 			if (shift) {
47 				op_array->opcodes[new_count] = *opline;
48 			}
49 			new_count++;
50 		}
51 	}
52 
53 	if (shift) {
54 		op_array->last = new_count;
55 		end = op_array->opcodes + op_array->last;
56 
57 		/* update JMPs */
58 		for (opline = op_array->opcodes; opline<end; opline++) {
59 			switch (opline->opcode) {
60 				case ZEND_JMP:
61 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
62 				case ZEND_GOTO:
63 #endif
64 #if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
65 				case ZEND_FAST_CALL:
66 #endif
67 					ZEND_OP1(opline).opline_num -= shiftlist[ZEND_OP1(opline).opline_num];
68 					break;
69 				case ZEND_JMPZ:
70 				case ZEND_JMPNZ:
71 				case ZEND_JMPZ_EX:
72 				case ZEND_JMPNZ_EX:
73 				case ZEND_FE_FETCH:
74 				case ZEND_FE_RESET:
75 				case ZEND_NEW:
76 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
77 				case ZEND_JMP_SET:
78 #endif
79 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
80 				case ZEND_JMP_SET_VAR:
81 #endif
82 					ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
83 					break;
84 				case ZEND_JMPZNZ:
85 					ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
86 					opline->extended_value -= shiftlist[opline->extended_value];
87 					break;
88 				case ZEND_CATCH:
89 					opline->extended_value -= shiftlist[opline->extended_value];
90 					break;
91 			}
92 		}
93 
94 		/* update brk/cont array */
95 		for (j = 0; j < op_array->last_brk_cont; j++) {
96 			op_array->brk_cont_array[j].brk -= shiftlist[op_array->brk_cont_array[j].brk];
97 			op_array->brk_cont_array[j].cont -= shiftlist[op_array->brk_cont_array[j].cont];
98 			op_array->brk_cont_array[j].start -= shiftlist[op_array->brk_cont_array[j].start];
99 		}
100 
101 		/* update try/catch array */
102 		for (j = 0; j < op_array->last_try_catch; j++) {
103 			op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op];
104 			op_array->try_catch_array[j].catch_op -= shiftlist[op_array->try_catch_array[j].catch_op];
105 #if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
106 			if (op_array->try_catch_array[j].finally_op) {
107 				op_array->try_catch_array[j].finally_op -= shiftlist[op_array->try_catch_array[j].finally_op];
108 				op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end];
109 			}
110 #endif
111 		}
112 
113 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
114 		/* update early binding list */
115 		if (op_array->early_binding != (zend_uint)-1) {
116 			zend_uint *opline_num = &op_array->early_binding;
117 
118 			do {
119 				*opline_num -= shiftlist[*opline_num];
120 				opline_num = &ZEND_RESULT(&op_array->opcodes[*opline_num]).opline_num;
121 			} while (*opline_num != (zend_uint)-1);
122 		}
123 #endif
124 	}
125 	FREE_ALLOCA(shiftlist);
126 }
127