1 /*
2 +----------------------------------------------------------------------+
3 | Zend OPcache |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2017 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@zend.com> |
16 | Zeev Suraski <zeev@zend.com> |
17 | Stanislav Malyshev <stas@zend.com> |
18 | Dmitry Stogov <dmitry@zend.com> |
19 +----------------------------------------------------------------------+
20 */
21
22 /* pass 2:
23 * - convert non-numeric constants to numeric constants in numeric operators
24 * - optimize constant conditional JMPs
25 * - optimize static BRKs and CONTs
26 */
27
28 #include "php.h"
29 #include "Optimizer/zend_optimizer.h"
30 #include "Optimizer/zend_optimizer_internal.h"
31 #include "zend_API.h"
32 #include "zend_constants.h"
33 #include "zend_execute.h"
34 #include "zend_vm.h"
35
zend_optimizer_pass2(zend_op_array * op_array)36 void zend_optimizer_pass2(zend_op_array *op_array)
37 {
38 zend_op *opline;
39 zend_op *end = op_array->opcodes + op_array->last;
40
41 opline = op_array->opcodes;
42 while (opline < end) {
43 switch (opline->opcode) {
44 case ZEND_ADD:
45 case ZEND_SUB:
46 case ZEND_MUL:
47 case ZEND_DIV:
48 case ZEND_POW:
49 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
50 if (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
51 convert_scalar_to_number(&ZEND_OP1_LITERAL(opline));
52 }
53 }
54 /* break missing *intentionally* - the assign_op's may only optimize op2 */
55 case ZEND_ASSIGN_ADD:
56 case ZEND_ASSIGN_SUB:
57 case ZEND_ASSIGN_MUL:
58 case ZEND_ASSIGN_DIV:
59 case ZEND_ASSIGN_POW:
60 if (opline->extended_value != 0) {
61 /* object tristate op - don't attempt to optimize it! */
62 break;
63 }
64 if (ZEND_OP2_TYPE(opline) == IS_CONST) {
65 if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
66 convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
67 }
68 }
69 break;
70
71 case ZEND_MOD:
72 case ZEND_SL:
73 case ZEND_SR:
74 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
75 if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_LONG) {
76 convert_to_long(&ZEND_OP1_LITERAL(opline));
77 }
78 }
79 /* break missing *intentionally - the assign_op's may only optimize op2 */
80 case ZEND_ASSIGN_MOD:
81 case ZEND_ASSIGN_SL:
82 case ZEND_ASSIGN_SR:
83 if (opline->extended_value != 0) {
84 /* object tristate op - don't attempt to optimize it! */
85 break;
86 }
87 if (ZEND_OP2_TYPE(opline) == IS_CONST) {
88 if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
89 convert_to_long(&ZEND_OP2_LITERAL(opline));
90 }
91 }
92 break;
93
94 case ZEND_CONCAT:
95 case ZEND_FAST_CONCAT:
96 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
97 if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
98 convert_to_string(&ZEND_OP1_LITERAL(opline));
99 }
100 }
101 /* break missing *intentionally - the assign_op's may only optimize op2 */
102 case ZEND_ASSIGN_CONCAT:
103 if (opline->extended_value != 0) {
104 /* object tristate op - don't attempt to optimize it! */
105 break;
106 }
107 if (ZEND_OP2_TYPE(opline) == IS_CONST) {
108 if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
109 convert_to_string(&ZEND_OP2_LITERAL(opline));
110 }
111 }
112 break;
113
114 case ZEND_JMPZ_EX:
115 case ZEND_JMPNZ_EX:
116 /* convert Ti = JMPZ_EX(Ti, L) to JMPZ(Ti, L) */
117 if (0 && /* FIXME: temporary disable unsafe pattern */
118 ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
119 ZEND_RESULT_TYPE(opline) == IS_TMP_VAR &&
120 ZEND_OP1(opline).var == ZEND_RESULT(opline).var) {
121 opline->opcode -= 3;
122 /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
123 in case we know it wouldn't jump */
124 } else if (ZEND_OP1_TYPE(opline) == IS_CONST) {
125 int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
126 if (opline->opcode == ZEND_JMPZ_EX) {
127 should_jmp = !should_jmp;
128 }
129 if (!should_jmp) {
130 opline->opcode = ZEND_QM_ASSIGN;
131 SET_UNUSED(opline->op2);
132 }
133 }
134 break;
135
136 case ZEND_JMPZ:
137 case ZEND_JMPNZ:
138 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
139 int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
140
141 if (opline->opcode == ZEND_JMPZ) {
142 should_jmp = !should_jmp;
143 }
144 literal_dtor(&ZEND_OP1_LITERAL(opline));
145 ZEND_OP1_TYPE(opline) = IS_UNUSED;
146 if (should_jmp) {
147 opline->opcode = ZEND_JMP;
148 COPY_NODE(opline->op1, opline->op2);
149 } else {
150 MAKE_NOP(opline);
151 }
152 break;
153 }
154 if ((opline + 1)->opcode == ZEND_JMP) {
155 /* JMPZ(X, L1), JMP(L2) => JMPZNZ(X, L1, L2) */
156 /* JMPNZ(X, L1), JMP(L2) => JMPZNZ(X, L2, L1) */
157 if (ZEND_OP2(opline).opline_num == ZEND_OP1(opline + 1).opline_num) {
158 /* JMPZ(X, L1), JMP(L1) => NOP, JMP(L1) */
159 if (opline->op1_type == IS_CV) {
160 break;
161 } else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
162 opline->opcode = ZEND_FREE;
163 opline->op2.num = 0;
164 } else {
165 MAKE_NOP(opline);
166 }
167 } else {
168 if (opline->opcode == ZEND_JMPZ) {
169 opline->extended_value = ZEND_OP1(opline + 1).opline_num;
170 } else {
171 opline->extended_value = ZEND_OP2(opline).opline_num;
172 COPY_NODE(opline->op2, (opline + 1)->op1);
173 }
174 opline->opcode = ZEND_JMPZNZ;
175 }
176 }
177 break;
178
179 case ZEND_JMPZNZ:
180 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
181 int opline_num;
182 if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
183 opline_num = opline->extended_value; /* JMPNZ */
184 } else {
185 opline_num = ZEND_OP2(opline).opline_num; /* JMPZ */
186 }
187 literal_dtor(&ZEND_OP1_LITERAL(opline));
188 ZEND_OP1(opline).opline_num = opline_num;
189 ZEND_OP1_TYPE(opline) = IS_UNUSED;
190 opline->opcode = ZEND_JMP;
191 }
192 break;
193 }
194 opline++;
195 }
196 }
197