1 /* pass 2:
2 * - convert non-numeric constants to numeric constants in numeric operators
3 * - optimize constant conditional JMPs
4 * - optimize static BRKs and CONTs
5 */
6
7 if (ZEND_OPTIMIZER_PASS_2 & OPTIMIZATION_LEVEL) {
8 zend_op *opline;
9 zend_op *end = op_array->opcodes + op_array->last;
10
11 opline = op_array->opcodes;
12 while (opline < end) {
13 switch (opline->opcode) {
14 case ZEND_ADD:
15 case ZEND_SUB:
16 case ZEND_MUL:
17 case ZEND_DIV:
18 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
19 if (ZEND_OP1_LITERAL(opline).type == IS_STRING) {
20 convert_scalar_to_number(&ZEND_OP1_LITERAL(opline) TSRMLS_CC);
21 }
22 }
23 /* break missing *intentionally* - the assign_op's may only optimize op2 */
24 case ZEND_ASSIGN_ADD:
25 case ZEND_ASSIGN_SUB:
26 case ZEND_ASSIGN_MUL:
27 case ZEND_ASSIGN_DIV:
28 if (opline->extended_value != 0) {
29 /* object tristate op - don't attempt to optimize it! */
30 break;
31 }
32 if (ZEND_OP2_TYPE(opline) == IS_CONST) {
33 if (ZEND_OP2_LITERAL(opline).type == IS_STRING) {
34 convert_scalar_to_number(&ZEND_OP2_LITERAL(opline) TSRMLS_CC);
35 }
36 }
37 break;
38
39 case ZEND_MOD:
40 case ZEND_SL:
41 case ZEND_SR:
42 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
43 if (ZEND_OP1_LITERAL(opline).type != IS_LONG) {
44 convert_to_long(&ZEND_OP1_LITERAL(opline));
45 }
46 }
47 /* break missing *intentionally - the assign_op's may only optimize op2 */
48 case ZEND_ASSIGN_MOD:
49 case ZEND_ASSIGN_SL:
50 case ZEND_ASSIGN_SR:
51 if (opline->extended_value != 0) {
52 /* object tristate op - don't attempt to optimize it! */
53 break;
54 }
55 if (ZEND_OP2_TYPE(opline) == IS_CONST) {
56 if (ZEND_OP2_LITERAL(opline).type != IS_LONG) {
57 convert_to_long(&ZEND_OP2_LITERAL(opline));
58 }
59 }
60 break;
61
62 case ZEND_CONCAT:
63 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
64 if (ZEND_OP1_LITERAL(opline).type != IS_STRING) {
65 convert_to_string(&ZEND_OP1_LITERAL(opline));
66 }
67 }
68 /* break missing *intentionally - the assign_op's may only optimize op2 */
69 case ZEND_ASSIGN_CONCAT:
70 if (opline->extended_value != 0) {
71 /* object tristate op - don't attempt to optimize it! */
72 break;
73 }
74 if (ZEND_OP2_TYPE(opline) == IS_CONST) {
75 if (ZEND_OP2_LITERAL(opline).type != IS_STRING) {
76 convert_to_string(&ZEND_OP2_LITERAL(opline));
77 }
78 }
79 break;
80
81 case ZEND_JMPZ_EX:
82 case ZEND_JMPNZ_EX:
83 /* convert Ti = JMPZ_EX(Ti, L) to JMPZ(Ti, L) */
84 if (0 && /* FIXME: temporary disable unsafe pattern */
85 ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
86 ZEND_RESULT_TYPE(opline) == IS_TMP_VAR &&
87 ZEND_OP1(opline).var == ZEND_RESULT(opline).var) {
88 opline->opcode -= 3;
89 /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
90 in case we know it wouldn't jump */
91 } else if (ZEND_OP1_TYPE(opline) == IS_CONST) {
92 int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
93 if (opline->opcode == ZEND_JMPZ_EX) {
94 should_jmp = !should_jmp;
95 }
96 if (!should_jmp) {
97 opline->opcode = ZEND_QM_ASSIGN;
98 SET_UNUSED(opline->op2);
99 }
100 }
101 break;
102
103 case ZEND_JMPZ:
104 case ZEND_JMPNZ:
105 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
106 int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
107
108 if (opline->opcode == ZEND_JMPZ) {
109 should_jmp = !should_jmp;
110 }
111 literal_dtor(&ZEND_OP1_LITERAL(opline));
112 ZEND_OP1_TYPE(opline) = IS_UNUSED;
113 if (should_jmp) {
114 opline->opcode = ZEND_JMP;
115 COPY_NODE(opline->op1, opline->op2);
116 } else {
117 MAKE_NOP(opline);
118 }
119 break;
120 }
121 if ((opline + 1)->opcode == ZEND_JMP) {
122 /* JMPZ(X, L1), JMP(L2) => JMPZNZ(X, L1, L2) */
123 /* JMPNZ(X, L1), JMP(L2) => JMPZNZ(X, L2, L1) */
124 if (ZEND_OP2(opline).opline_num == ZEND_OP1(opline + 1).opline_num) {
125 /* JMPZ(X, L1), JMP(L1) => NOP, JMP(L1) */
126 MAKE_NOP(opline);
127 } else {
128 if (opline->opcode == ZEND_JMPZ) {
129 opline->extended_value = ZEND_OP1(opline + 1).opline_num;
130 } else {
131 opline->extended_value = ZEND_OP2(opline).opline_num;
132 COPY_NODE(opline->op2, (opline + 1)->op1);
133 }
134 opline->opcode = ZEND_JMPZNZ;
135 }
136 }
137 break;
138
139 case ZEND_JMPZNZ:
140 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
141 int opline_num;
142
143 if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
144 opline_num = opline->extended_value; /* JMPNZ */
145 } else {
146 opline_num = ZEND_OP2(opline).opline_num; /* JMPZ */
147 }
148 literal_dtor(&ZEND_OP1_LITERAL(opline));
149 ZEND_OP1(opline).opline_num = opline_num;
150 ZEND_OP1_TYPE(opline) = IS_UNUSED;
151 opline->opcode = ZEND_JMP;
152 }
153 break;
154
155 case ZEND_BRK:
156 case ZEND_CONT:
157 {
158 zend_brk_cont_element *jmp_to;
159 int array_offset;
160 int nest_levels;
161 int dont_optimize = 0;
162
163 if (ZEND_OP2_TYPE(opline) != IS_CONST) {
164 break;
165 }
166 convert_to_long(&ZEND_OP2_LITERAL(opline));
167 nest_levels = ZEND_OP2_LITERAL(opline).value.lval;
168
169 array_offset = ZEND_OP1(opline).opline_num;
170 while (1) {
171 if (array_offset == -1) {
172 dont_optimize = 1; /* don't optimize this bogus break/continue, let the executor shout */
173 break;
174 }
175 jmp_to = &op_array->brk_cont_array[array_offset];
176 array_offset = jmp_to->parent;
177 if (--nest_levels > 0) {
178 if (op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE ||
179 op_array->opcodes[jmp_to->brk].opcode == ZEND_SWITCH_FREE
180 ) {
181 dont_optimize = 1;
182 break;
183 }
184 } else {
185 break;
186 }
187 }
188
189 if (dont_optimize) {
190 break;
191 }
192
193 /* optimize - convert to a JMP */
194 switch (opline->opcode) {
195 case ZEND_BRK:
196 MAKE_NOP(opline);
197 ZEND_OP1(opline).opline_num = jmp_to->brk;
198 break;
199 case ZEND_CONT:
200 MAKE_NOP(opline);
201 ZEND_OP1(opline).opline_num = jmp_to->cont;
202 break;
203 }
204 opline->opcode = ZEND_JMP;
205 /* MAKE_NOP() already set op1 and op2 to IS_UNUSED */
206 }
207 break;
208 }
209 opline++;
210 }
211 }