1 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
2
3 /* ops that use CLs:
4 op1:
5 ZEND_FETCH_CONSTANT:
6 ZEND_INIT_CTOR_CALL:
7 ZEND_INIT_STATIC_METHOD_CALL:
8 ZEND_INIT_METHOD_CALL:
9 ZEND_IMPORT_CLASS:
10 ZEND_IMPORT_FUNCTION:
11 ZEND_IMPORT_CONST:
12 ZEND_ADD_INTERFACE:
13 ZEND_VERIFY_ABSTRACT_CLASS:
14 ZEND_NEW:
15 ZEND_CATCH:
16 ZEND_INIT_FCALL_BY_NAME:
17
18 op2:
19 ZEND_UNSET_VAR:
20 ZEND_ISSET_ISEMPTY_VAR:
21 ZEND_FETCH_UNSET:
22 ZEND_FETCH_IS:
23 ZEND_FETCH_R:
24 ZEND_FETCH_W:
25 ZEND_FETCH_RW:
26 ZEND_FETCH_FUNC_ARG:
27 ZEND_ADD_INTERFACE:
28 ZEND_INSTANCEOF:
29
30 extended_value:
31 ZEND_DECLARE_INHERITED_CLASS:
32
33 ignore result
34 INIT_METHOD_CALL:
35 */
36
37 #define OP1_CONST_IS_CLASS 1
38 #define OP2_CONST_IS_CLASS 2
39 #define EXT_CONST_IS_CLASS 4
40 #define RESULT_IS_UNUSED 8
41
42 static const char op_const_means_class[256] = {
43 /* 0 */
44 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45 /* 32 */
46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
47 /* 64 */
48 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2,
49 /* 96 */
50 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 9, 1, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51 /* 128 */
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53 /* 160 */
54 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55 /* 192 */
56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57 /* 224 */
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
59 };
60 #endif
61
62 #define GET_AVAILABLE_T() \
63 for (i = 0; i < T; i++) { \
64 if (!taken_T[i]) { \
65 break; \
66 } \
67 } \
68 taken_T[i] = 1; \
69 if (i > max) { \
70 max = i; \
71 }
72
optimize_temporary_variables(zend_op_array * op_array)73 static void optimize_temporary_variables(zend_op_array *op_array)
74 {
75 int T = op_array->T;
76 char *taken_T; /* T index in use */
77 zend_op **start_of_T; /* opline where T is first used */
78 char *valid_T; /* Is the map_T valid */
79 int *map_T; /* Map's the T to its new index */
80 zend_op *opline, *end;
81 int currT;
82 int i;
83 int max = -1;
84 int var_to_free = -1;
85
86 taken_T = (char *) emalloc(T);
87 start_of_T = (zend_op **) emalloc(T * sizeof(zend_op *));
88 valid_T = (char *) emalloc(T);
89 map_T = (int *) emalloc(T * sizeof(int));
90
91 end = op_array->opcodes;
92 opline = &op_array->opcodes[op_array->last - 1];
93
94 /* Find T definition points */
95 while (opline >= end) {
96 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
97 if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) {
98 if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) {
99 start_of_T[VAR_NUM(ZEND_RESULT(opline).var)] = opline;
100 }
101 }
102 #else
103 if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
104 start_of_T[VAR_NUM(ZEND_RESULT(opline).var)] = opline;
105 }
106 #endif
107 opline--;
108 }
109
110 memset(valid_T, 0, T);
111 memset(taken_T, 0, T);
112
113 end = op_array->opcodes;
114 opline = &op_array->opcodes[op_array->last - 1];
115
116 while (opline >= end) {
117 if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))
118 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
119 || ((op_const_means_class[opline->opcode] & OP1_CONST_IS_CLASS) && ZEND_OP1_TYPE(opline) == IS_CONST)
120 #endif
121 ) {
122 currT = VAR_NUM(ZEND_OP1(opline).var);
123 if (!valid_T[currT]) {
124 GET_AVAILABLE_T();
125 map_T[currT] = i;
126 valid_T[currT] = 1;
127 }
128 ZEND_OP1(opline).var = NUM_VAR(map_T[currT]);
129 }
130
131 /* Skip OP_DATA */
132 if (opline->opcode == ZEND_OP_DATA &&
133 (opline-1)->opcode == ZEND_ASSIGN_DIM) {
134 opline--;
135 continue;
136 }
137
138 if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR))
139 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
140 || ((op_const_means_class[opline->opcode] & OP2_CONST_IS_CLASS) && ZEND_OP2_TYPE(opline) == IS_CONST)
141 #endif
142 ) {
143 currT = VAR_NUM(ZEND_OP2(opline).var);
144 if (!valid_T[currT]) {
145 GET_AVAILABLE_T();
146 map_T[currT] = i;
147 valid_T[currT] = 1;
148 }
149 ZEND_OP2(opline).var = NUM_VAR(map_T[currT]);
150 }
151
152 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
153 if ((op_const_means_class[opline->opcode] & EXT_CONST_IS_CLASS)) {
154 #else
155 if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS ||
156 opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
157 #endif
158 currT = VAR_NUM(opline->extended_value);
159 if (!valid_T[currT]) {
160 GET_AVAILABLE_T();
161 map_T[currT] = i;
162 valid_T[currT] = 1;
163 }
164 opline->extended_value = NUM_VAR(map_T[currT]);
165 }
166
167 /* Allocate OP_DATA->op2 after "operands", but before "result" */
168 if (opline->opcode == ZEND_ASSIGN_DIM &&
169 (opline + 1)->opcode == ZEND_OP_DATA &&
170 ZEND_OP2_TYPE(opline + 1) & (IS_VAR | IS_TMP_VAR)) {
171 currT = VAR_NUM(ZEND_OP2(opline + 1).var);
172 GET_AVAILABLE_T();
173 map_T[currT] = i;
174 valid_T[currT] = 1;
175 taken_T[i] = 0;
176 ZEND_OP2(opline + 1).var = NUM_VAR(i);
177 var_to_free = i;
178 }
179
180 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
181 if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) {
182 if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) {
183 #else
184 if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
185 #endif
186 currT = VAR_NUM(ZEND_RESULT(opline).var);
187 if (valid_T[currT]) {
188 if (start_of_T[currT] == opline) {
189 taken_T[map_T[currT]] = 0;
190 }
191 ZEND_RESULT(opline).var = NUM_VAR(map_T[currT]);
192 } else { /* Au still needs to be assigned a T which is a bit dumb. Should consider changing Zend */
193 GET_AVAILABLE_T();
194
195 if (RESULT_UNUSED(opline)) {
196 taken_T[i] = 0;
197 } else {
198 /* Code which gets here is using a wrongly built opcode such as RECV() */
199 map_T[currT] = i;
200 valid_T[currT] = 1;
201 }
202 ZEND_RESULT(opline).var = NUM_VAR(i);
203 }
204 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
205 }
206 #endif
207 }
208
209 if (var_to_free >= 0) {
210 taken_T[var_to_free] = 0;
211 var_to_free = -1;
212 }
213
214 opline--;
215 }
216
217 efree(taken_T);
218 efree(start_of_T);
219 efree(valid_T);
220 efree(map_T);
221 op_array->T = max + 1;
222 }
223