1 /*
2 +----------------------------------------------------------------------+
3 | Zend OPcache |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2016 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 #include "php.h"
23 #include "Optimizer/zend_optimizer.h"
24 #include "Optimizer/zend_optimizer_internal.h"
25 #include "zend_API.h"
26 #include "zend_constants.h"
27 #include "zend_execute.h"
28 #include "zend_vm.h"
29
30 #define OPTIMIZATION_LEVEL \
31 ZCG(accel_directives).optimization_level
32
zend_optimizer_zval_dtor_wrapper(zval * zvalue)33 static void zend_optimizer_zval_dtor_wrapper(zval *zvalue)
34 {
35 zval_dtor(zvalue);
36 }
37
zend_optimizer_collect_constant(HashTable ** constants,zval * name,zval * value)38 static void zend_optimizer_collect_constant(HashTable **constants, zval *name, zval* value)
39 {
40 zval val;
41
42 if (!*constants) {
43 *constants = emalloc(sizeof(HashTable));
44 zend_hash_init(*constants, 16, NULL, (void (*)(void *))zend_optimizer_zval_dtor_wrapper, 0);
45 }
46 val = *value;
47 zval_copy_ctor(&val);
48 zend_hash_add(*constants, Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void**)&val, sizeof(zval), NULL);
49 }
50
zend_optimizer_get_collected_constant(HashTable * constants,zval * name,zval * value)51 static int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value)
52 {
53 zval *val;
54
55 if (zend_hash_find(constants, Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void**)&val) == SUCCESS) {
56 *value = *val;
57 zval_copy_ctor(value);
58 return 1;
59 }
60 return 0;
61 }
62
63 #if ZEND_EXTENSION_API_NO >= PHP_5_5_X_API_NO
zend_optimizer_lookup_cv(zend_op_array * op_array,char * name,int name_len)64 static int zend_optimizer_lookup_cv(zend_op_array *op_array, char* name, int name_len)
65 {
66 int i = 0;
67 ulong hash_value = zend_inline_hash_func(name, name_len+1);
68
69 while (i < op_array->last_var) {
70 if (op_array->vars[i].name == name ||
71 (op_array->vars[i].hash_value == hash_value &&
72 op_array->vars[i].name_len == name_len &&
73 memcmp(op_array->vars[i].name, name, name_len) == 0)) {
74 return i;
75 }
76 i++;
77 }
78 i = op_array->last_var;
79 op_array->last_var++;
80 op_array->vars = erealloc(op_array->vars, op_array->last_var * sizeof(zend_compiled_variable));
81 if (IS_INTERNED(name)) {
82 op_array->vars[i].name = name;
83 } else {
84 op_array->vars[i].name = estrndup(name, name_len);
85 }
86 op_array->vars[i].name_len = name_len;
87 op_array->vars[i].hash_value = hash_value;
88 return i;
89 }
90 #endif
91
92 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
zend_optimizer_add_literal(zend_op_array * op_array,const zval * zv TSRMLS_DC)93 int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC)
94 {
95 int i = op_array->last_literal;
96 op_array->last_literal++;
97 op_array->literals = (zend_literal*)erealloc(op_array->literals, op_array->last_literal * sizeof(zend_literal));
98 op_array->literals[i].constant = *zv;
99 op_array->literals[i].hash_value = 0;
100 op_array->literals[i].cache_slot = -1;
101 Z_SET_REFCOUNT(op_array->literals[i].constant, 2);
102 Z_SET_ISREF(op_array->literals[i].constant);
103 return i;
104 }
105
106 # define LITERAL_LONG(op, val) do { \
107 zval _c; \
108 ZVAL_LONG(&_c, val); \
109 op.constant = zend_optimizer_add_literal(op_array, &_c TSRMLS_CC); \
110 } while (0)
111
112 # define LITERAL_BOOL(op, val) do { \
113 zval _c; \
114 ZVAL_BOOL(&_c, val); \
115 op.constant = zend_optimizer_add_literal(op_array, &_c TSRMLS_CC); \
116 } while (0)
117
118 # define literal_dtor(zv) do { \
119 zval_dtor(zv); \
120 Z_TYPE_P(zv) = IS_NULL; \
121 } while (0)
122
123 #define COPY_NODE(target, src) do { \
124 target ## _type = src ## _type; \
125 target = src; \
126 } while (0)
127
128 #else
129
130 # define LITERAL_LONG(op, val) ZVAL_LONG(&op.u.constant, val)
131
132 # define LITERAL_BOOL(op, val) ZVAL_BOOL(&op.u.constant, val)
133
134 # define literal_dtor(zv) zval_dtor(zv)
135
136 #define COPY_NODE(target, src) do { \
137 target = src; \
138 } while (0)
139
140 #endif
141
update_op1_const(zend_op_array * op_array,zend_op * opline,zval * val TSRMLS_DC)142 static void update_op1_const(zend_op_array *op_array,
143 zend_op *opline,
144 zval *val TSRMLS_DC)
145 {
146 if (opline->opcode == ZEND_FREE) {
147 MAKE_NOP(opline);
148 zval_dtor(val);
149 } else {
150 ZEND_OP1_TYPE(opline) = IS_CONST;
151 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
152 if (Z_TYPE_P(val) == IS_STRING) {
153 switch (opline->opcode) {
154 case ZEND_INIT_STATIC_METHOD_CALL:
155 case ZEND_CATCH:
156 case ZEND_FETCH_CONSTANT:
157 opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
158 Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
159 op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;
160 Z_STRVAL_P(val) = zend_str_tolower_dup(Z_STRVAL_P(val), Z_STRLEN_P(val));
161 zend_optimizer_add_literal(op_array, val TSRMLS_CC);
162 op_array->literals[opline->op1.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op1.constant+1].constant), Z_STRLEN(op_array->literals[opline->op1.constant+1].constant) + 1);
163 break;
164 case ZEND_DO_FCALL:
165 zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
166 opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
167 Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
168 op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;
169 break;
170 default:
171 opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
172 Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
173 break;
174 }
175 } else {
176 opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
177 }
178 #else
179 ZEND_OP1_LITERAL(opline) = *val;
180 #endif
181 }
182 }
183
update_op2_const(zend_op_array * op_array,zend_op * opline,zval * val TSRMLS_DC)184 static void update_op2_const(zend_op_array *op_array,
185 zend_op *opline,
186 zval *val TSRMLS_DC)
187 {
188 ZEND_OP2_TYPE(opline) = IS_CONST;
189 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
190 opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
191 if (Z_TYPE_P(val) == IS_STRING) {
192 Z_HASH_P(&ZEND_OP2_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)) + 1);
193 switch (opline->opcode) {
194 case ZEND_FETCH_R:
195 case ZEND_FETCH_W:
196 case ZEND_FETCH_RW:
197 case ZEND_FETCH_IS:
198 case ZEND_FETCH_UNSET:
199 case ZEND_FETCH_FUNC_ARG:
200 case ZEND_FETCH_CLASS:
201 case ZEND_INIT_FCALL_BY_NAME:
202 /*case ZEND_INIT_NS_FCALL_BY_NAME:*/
203 case ZEND_UNSET_VAR:
204 case ZEND_ISSET_ISEMPTY_VAR:
205 case ZEND_ADD_INTERFACE:
206 case ZEND_ADD_TRAIT:
207 op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot++;
208 Z_STRVAL_P(val) = zend_str_tolower_dup(Z_STRVAL_P(val), Z_STRLEN_P(val));
209 zend_optimizer_add_literal(op_array, val TSRMLS_CC);
210 op_array->literals[opline->op2.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op2.constant+1].constant), Z_STRLEN(op_array->literals[opline->op2.constant+1].constant) + 1);
211 break;
212 case ZEND_INIT_METHOD_CALL:
213 case ZEND_INIT_STATIC_METHOD_CALL:
214 Z_STRVAL_P(val) = zend_str_tolower_dup(Z_STRVAL_P(val), Z_STRLEN_P(val));
215 zend_optimizer_add_literal(op_array, val TSRMLS_CC);
216 op_array->literals[opline->op2.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op2.constant+1].constant), Z_STRLEN(op_array->literals[opline->op2.constant+1].constant) + 1);
217 /* break missing intentionally */
218 /*case ZEND_FETCH_CONSTANT:*/
219 case ZEND_ASSIGN_OBJ:
220 case ZEND_FETCH_OBJ_R:
221 case ZEND_FETCH_OBJ_W:
222 case ZEND_FETCH_OBJ_RW:
223 case ZEND_FETCH_OBJ_IS:
224 case ZEND_FETCH_OBJ_UNSET:
225 case ZEND_FETCH_OBJ_FUNC_ARG:
226 case ZEND_UNSET_OBJ:
227 case ZEND_PRE_INC_OBJ:
228 case ZEND_PRE_DEC_OBJ:
229 case ZEND_POST_INC_OBJ:
230 case ZEND_POST_DEC_OBJ:
231 case ZEND_ISSET_ISEMPTY_PROP_OBJ:
232 op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;
233 op_array->last_cache_slot += 2;
234 break;
235 case ZEND_ASSIGN_ADD:
236 case ZEND_ASSIGN_SUB:
237 case ZEND_ASSIGN_MUL:
238 case ZEND_ASSIGN_DIV:
239 case ZEND_ASSIGN_MOD:
240 case ZEND_ASSIGN_SL:
241 case ZEND_ASSIGN_SR:
242 case ZEND_ASSIGN_CONCAT:
243 case ZEND_ASSIGN_BW_OR:
244 case ZEND_ASSIGN_BW_AND:
245 case ZEND_ASSIGN_BW_XOR:
246 if (opline->extended_value == ZEND_ASSIGN_OBJ) {
247 op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;
248 op_array->last_cache_slot += 2;
249 }
250 break;
251 #if ZEND_EXTENSION_API_NO >= PHP_5_4_X_API_NO
252 case ZEND_OP_DATA:
253 if ((opline-1)->opcode == ZEND_ASSIGN_DIM ||
254 ((opline-1)->extended_value == ZEND_ASSIGN_DIM &&
255 ((opline-1)->opcode == ZEND_ASSIGN_ADD ||
256 (opline-1)->opcode == ZEND_ASSIGN_SUB ||
257 (opline-1)->opcode == ZEND_ASSIGN_MUL ||
258 (opline-1)->opcode == ZEND_ASSIGN_DIV ||
259 (opline-1)->opcode == ZEND_ASSIGN_MOD ||
260 (opline-1)->opcode == ZEND_ASSIGN_SL ||
261 (opline-1)->opcode == ZEND_ASSIGN_SR ||
262 (opline-1)->opcode == ZEND_ASSIGN_CONCAT ||
263 (opline-1)->opcode == ZEND_ASSIGN_BW_OR ||
264 (opline-1)->opcode == ZEND_ASSIGN_BW_AND ||
265 (opline-1)->opcode == ZEND_ASSIGN_BW_XOR))) {
266 goto check_numeric;
267 }
268 break;
269 case ZEND_ISSET_ISEMPTY_DIM_OBJ:
270 case ZEND_ADD_ARRAY_ELEMENT:
271 case ZEND_INIT_ARRAY:
272 case ZEND_ASSIGN_DIM:
273 case ZEND_UNSET_DIM:
274 case ZEND_FETCH_DIM_R:
275 case ZEND_FETCH_DIM_W:
276 case ZEND_FETCH_DIM_RW:
277 case ZEND_FETCH_DIM_IS:
278 case ZEND_FETCH_DIM_FUNC_ARG:
279 case ZEND_FETCH_DIM_UNSET:
280 case ZEND_FETCH_DIM_TMP_VAR:
281 check_numeric:
282 {
283 ulong index;
284 int numeric = 0;
285
286 ZEND_HANDLE_NUMERIC_EX(Z_STRVAL_P(val), Z_STRLEN_P(val)+1, index, numeric = 1);
287 if (numeric) {
288 zval_dtor(val);
289 ZVAL_LONG(val, index);
290 op_array->literals[opline->op2.constant].constant = *val;
291 }
292 }
293 break;
294 #endif
295 default:
296 break;
297 }
298 }
299 #else
300 ZEND_OP2_LITERAL(opline) = *val;
301 #endif
302 }
303
replace_var_by_const(zend_op_array * op_array,zend_op * opline,zend_uint var,zval * val TSRMLS_DC)304 static int replace_var_by_const(zend_op_array *op_array,
305 zend_op *opline,
306 zend_uint var,
307 zval *val TSRMLS_DC)
308 {
309 zend_op *end = op_array->opcodes + op_array->last;
310
311 while (opline < end) {
312 if (ZEND_OP1_TYPE(opline) == IS_VAR &&
313 ZEND_OP1(opline).var == var) {
314 switch (opline->opcode) {
315 case ZEND_FETCH_DIM_W:
316 case ZEND_FETCH_DIM_RW:
317 case ZEND_FETCH_DIM_FUNC_ARG:
318 case ZEND_FETCH_DIM_UNSET:
319 case ZEND_ASSIGN_DIM:
320 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
321 case ZEND_SEPARATE:
322 #endif
323 return 0;
324 case ZEND_SEND_VAR_NO_REF:
325 if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) {
326 if (opline->extended_value & ZEND_ARG_SEND_BY_REF) {
327 return 0;
328 }
329 opline->extended_value = ZEND_DO_FCALL;
330 } else {
331 opline->extended_value = ZEND_DO_FCALL_BY_NAME;
332 }
333 opline->opcode = ZEND_SEND_VAL;
334 break;
335 case ZEND_SWITCH_FREE:
336 case ZEND_CASE: {
337 zend_op *m, *n;
338 int brk = op_array->last_brk_cont;
339 while (brk--) {
340 if (op_array->brk_cont_array[brk].start <= (opline - op_array->opcodes) &&
341 op_array->brk_cont_array[brk].brk > (opline - op_array->opcodes)) {
342 break;
343 }
344 }
345 m = opline;
346 n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1;
347 while (m < n) {
348 if (ZEND_OP1_TYPE(m) == IS_VAR &&
349 ZEND_OP1(m).var == var) {
350 if (m->opcode == ZEND_CASE) {
351 zval old_val;
352 old_val = *val;
353 zval_copy_ctor(val);
354 update_op1_const(op_array, m, val TSRMLS_CC);
355 *val = old_val;
356 } else if (m->opcode == ZEND_SWITCH_FREE) {
357 MAKE_NOP(m);
358 } else {
359 ZEND_ASSERT(0);
360 }
361 }
362 m++;
363 }
364 zval_dtor(val);
365 return 1;
366 }
367 case ZEND_FREE:
368 MAKE_NOP(opline);
369 zval_dtor(val);
370 break;
371 default:
372 break;
373 }
374 update_op1_const(op_array, opline, val TSRMLS_CC);
375 break;
376 }
377
378 if (ZEND_OP2_TYPE(opline) == IS_VAR &&
379 ZEND_OP2(opline).var == var) {
380 switch (opline->opcode) {
381 case ZEND_ASSIGN_REF:
382 return 0;
383 default:
384 break;
385 }
386 update_op2_const(op_array, opline, val TSRMLS_CC);
387 break;
388 }
389 opline++;
390 }
391
392 return 1;
393 }
394
replace_tmp_by_const(zend_op_array * op_array,zend_op * opline,zend_uint var,zval * val TSRMLS_DC)395 static void replace_tmp_by_const(zend_op_array *op_array,
396 zend_op *opline,
397 zend_uint var,
398 zval *val
399 TSRMLS_DC)
400 {
401 zend_op *end = op_array->opcodes + op_array->last;
402
403 while (opline < end) {
404 if (ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
405 ZEND_OP1(opline).var == var) {
406
407 /* In most cases IS_TMP_VAR operand may be used only once.
408 * The operands are usually destroyed by the opcode handler.
409 * ZEND_CASE is an exception, that keeps operand unchanged,
410 * and allows its reuse. The number of ZEND_CASE instructions
411 * usually terminated by ZEND_FREE that finally kills the value.
412 */
413 if (opline->opcode == ZEND_CASE || opline->opcode == ZEND_FREE) {
414 zend_op *m, *n;
415 int brk = op_array->last_brk_cont;
416 zend_bool in_switch = 0;
417 while (brk--) {
418 if (op_array->brk_cont_array[brk].start <= (opline - op_array->opcodes) &&
419 op_array->brk_cont_array[brk].brk > (opline - op_array->opcodes)) {
420 in_switch = 1;
421 break;
422 }
423 }
424
425 if (!in_switch) {
426 MAKE_NOP(opline);
427 zval_dtor(val);
428 break;
429 }
430
431 m = opline;
432 n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1;
433 while (m < n) {
434 if (ZEND_OP1_TYPE(m) == IS_TMP_VAR &&
435 ZEND_OP1(m).var == var) {
436 if (m->opcode == ZEND_CASE) {
437 zval old_val;
438 old_val = *val;
439 zval_copy_ctor(val);
440 update_op1_const(op_array, m, val TSRMLS_CC);
441 *val = old_val;
442 } else if (m->opcode == ZEND_FREE) {
443 MAKE_NOP(m);
444 } else {
445 ZEND_ASSERT(0);
446 }
447 }
448 m++;
449 }
450 zval_dtor(val);
451 break;
452 } else {
453 update_op1_const(op_array, opline, val TSRMLS_CC);
454 break;
455 }
456 }
457
458 if (ZEND_OP2_TYPE(opline) == IS_TMP_VAR &&
459 ZEND_OP2(opline).var == var) {
460
461 update_op2_const(op_array, opline, val TSRMLS_CC);
462 /* TMP_VAR may be used only once */
463 break;
464 }
465 opline++;
466 }
467 }
468
469 #include "Optimizer/nop_removal.c"
470 #include "Optimizer/block_pass.c"
471 #include "Optimizer/optimize_temp_vars_5.c"
472 #include "Optimizer/compact_literals.c"
473 #include "Optimizer/optimize_func_calls.c"
474
zend_optimize(zend_op_array * op_array,zend_persistent_script * script,HashTable ** constants TSRMLS_DC)475 static void zend_optimize(zend_op_array *op_array,
476 zend_persistent_script *script,
477 HashTable **constants TSRMLS_DC)
478 {
479 if (op_array->type == ZEND_EVAL_CODE ||
480 (op_array->fn_flags & ZEND_ACC_INTERACTIVE)) {
481 return;
482 }
483
484 /* pass 1
485 * - substitute persistent constants (true, false, null, etc)
486 * - perform compile-time evaluation of constant binary and unary operations
487 * - optimize series of ADD_STRING and/or ADD_CHAR
488 * - convert CAST(IS_BOOL,x) into BOOL(x)
489 */
490 #include "Optimizer/pass1_5.c"
491
492 /* pass 2:
493 * - convert non-numeric constants to numeric constants in numeric operators
494 * - optimize constant conditional JMPs
495 * - optimize static BRKs and CONTs
496 * - pre-evaluate constant function calls
497 */
498 #include "Optimizer/pass2.c"
499
500 /* pass 3:
501 * - optimize $i = $i+expr to $i+=expr
502 * - optimize series of JMPs
503 * - change $i++ to ++$i where possible
504 */
505 #include "Optimizer/pass3.c"
506
507 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
508 /* pass 4:
509 * - INIT_FCALL_BY_NAME -> DO_FCALL
510 */
511 if (ZEND_OPTIMIZER_PASS_4 & OPTIMIZATION_LEVEL) {
512 optimize_func_calls(op_array, script TSRMLS_CC);
513 }
514 #endif
515
516 /* pass 5:
517 * - CFG optimization
518 */
519 #include "Optimizer/pass5.c"
520
521 /* pass 9:
522 * - Optimize temp variables usage
523 */
524 #include "Optimizer/pass9.c"
525
526 /* pass 10:
527 * - remove NOPs
528 */
529 #include "Optimizer/pass10.c"
530
531 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
532 /* pass 11:
533 * - Compact literals table
534 */
535 if (ZEND_OPTIMIZER_PASS_11 & OPTIMIZATION_LEVEL) {
536 optimizer_compact_literals(op_array TSRMLS_CC);
537 }
538 #endif
539 }
540
zend_accel_optimize(zend_op_array * op_array,zend_persistent_script * script,HashTable ** constants TSRMLS_DC)541 static void zend_accel_optimize(zend_op_array *op_array,
542 zend_persistent_script *script,
543 HashTable **constants TSRMLS_DC)
544 {
545 zend_op *opline, *end;
546
547 /* Revert pass_two() */
548 opline = op_array->opcodes;
549 end = opline + op_array->last;
550 while (opline < end) {
551 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
552 if (opline->op1_type == IS_CONST) {
553 opline->op1.constant = opline->op1.literal - op_array->literals;
554 }
555 if (opline->op2_type == IS_CONST) {
556 opline->op2.constant = opline->op2.literal - op_array->literals;
557 }
558 #endif
559 switch (opline->opcode) {
560 case ZEND_JMP:
561 #if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO
562 case ZEND_GOTO:
563 #endif
564 #if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
565 case ZEND_FAST_CALL:
566 #endif
567 ZEND_OP1(opline).opline_num = ZEND_OP1(opline).jmp_addr - op_array->opcodes;
568 break;
569 case ZEND_JMPZ:
570 case ZEND_JMPNZ:
571 case ZEND_JMPZ_EX:
572 case ZEND_JMPNZ_EX:
573 #if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO
574 case ZEND_JMP_SET:
575 #endif
576 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
577 case ZEND_JMP_SET_VAR:
578 #endif
579 ZEND_OP2(opline).opline_num = ZEND_OP2(opline).jmp_addr - op_array->opcodes;
580 break;
581 }
582 opline++;
583 }
584
585 /* Do actual optimizations */
586 zend_optimize(op_array, script, constants TSRMLS_CC);
587
588 /* Redo pass_two() */
589 opline = op_array->opcodes;
590 end = opline + op_array->last;
591 while (opline < end) {
592 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
593 if (opline->op1_type == IS_CONST) {
594 opline->op1.zv = &op_array->literals[opline->op1.constant].constant;
595 }
596 if (opline->op2_type == IS_CONST) {
597 opline->op2.zv = &op_array->literals[opline->op2.constant].constant;
598 }
599 #endif
600 switch (opline->opcode) {
601 case ZEND_JMP:
602 #if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO
603 case ZEND_GOTO:
604 #endif
605 #if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
606 case ZEND_FAST_CALL:
607 #endif
608 ZEND_OP1(opline).jmp_addr = &op_array->opcodes[ZEND_OP1(opline).opline_num];
609 break;
610 case ZEND_JMPZ:
611 case ZEND_JMPNZ:
612 case ZEND_JMPZ_EX:
613 case ZEND_JMPNZ_EX:
614 #if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO
615 case ZEND_JMP_SET:
616 #endif
617 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
618 case ZEND_JMP_SET_VAR:
619 #endif
620 ZEND_OP2(opline).jmp_addr = &op_array->opcodes[ZEND_OP2(opline).opline_num];
621 break;
622 }
623 ZEND_VM_SET_OPCODE_HANDLER(opline);
624 opline++;
625 }
626 }
627
zend_accel_script_optimize(zend_persistent_script * script TSRMLS_DC)628 int zend_accel_script_optimize(zend_persistent_script *script TSRMLS_DC)
629 {
630 Bucket *p, *q;
631 HashTable *constants = NULL;
632
633 zend_accel_optimize(&script->main_op_array, script, &constants TSRMLS_CC);
634
635 p = script->function_table.pListHead;
636 while (p) {
637 zend_op_array *op_array = (zend_op_array*)p->pData;
638 zend_accel_optimize(op_array, script, &constants TSRMLS_CC);
639 p = p->pListNext;
640 }
641
642 p = script->class_table.pListHead;
643 while (p) {
644 zend_class_entry *ce = (zend_class_entry*)p->pDataPtr;
645 q = ce->function_table.pListHead;
646 while (q) {
647 zend_op_array *op_array = (zend_op_array*)q->pData;
648 if (op_array->scope == ce) {
649 zend_accel_optimize(op_array, script, &constants TSRMLS_CC);
650 } else if (op_array->type == ZEND_USER_FUNCTION) {
651 zend_op_array *orig_op_array;
652 if (zend_hash_find(&op_array->scope->function_table, q->arKey, q->nKeyLength, (void**)&orig_op_array) == SUCCESS) {
653 HashTable *ht = op_array->static_variables;
654 *op_array = *orig_op_array;
655 op_array->static_variables = ht;
656 }
657 }
658 q = q->pListNext;
659 }
660 p = p->pListNext;
661 }
662
663 if (constants) {
664 zend_hash_destroy(constants);
665 efree(constants);
666 }
667
668 return 1;
669 }
670