This source file includes following definitions.
- zend_optimizer_zval_dtor_wrapper
- zend_optimizer_collect_constant
- zend_optimizer_get_collected_constant
- zend_optimizer_lookup_cv
- zend_optimizer_add_literal
- zend_optimizer_add_literal_string
- zend_optimizer_is_disabled_func
- drop_leading_backslash
- alloc_cache_slots_op1
- alloc_cache_slots_op2
- zend_optimizer_update_op1_const
- zend_optimizer_update_op2_const
- zend_optimizer_replace_by_const
- zend_optimize
- zend_accel_optimize
- zend_accel_adjust_fcall_stack_size
- zend_accel_script_optimize
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 static void zend_optimizer_zval_dtor_wrapper(zval *zvalue)
31 {
32 zval_dtor(zvalue);
33 }
34
35 void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval* value)
36 {
37 zval val;
38
39 if (!ctx->constants) {
40 ctx->constants = zend_arena_alloc(&ctx->arena, sizeof(HashTable));
41 zend_hash_init(ctx->constants, 16, NULL, zend_optimizer_zval_dtor_wrapper, 0);
42 }
43 ZVAL_DUP(&val, value);
44 zend_hash_add(ctx->constants, Z_STR_P(name), &val);
45 }
46
47 int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value)
48 {
49 zval *val;
50
51 if ((val = zend_hash_find(constants, Z_STR_P(name))) != NULL) {
52 ZVAL_DUP(value, val);
53 return 1;
54 }
55 return 0;
56 }
57
58 int zend_optimizer_lookup_cv(zend_op_array *op_array, zend_string* name)
59 {
60 int i = 0;
61 zend_ulong hash_value = zend_string_hash_val(name);
62
63 while (i < op_array->last_var) {
64 if (op_array->vars[i] == name ||
65 (ZSTR_H(op_array->vars[i]) == hash_value &&
66 ZSTR_LEN(op_array->vars[i]) == ZSTR_LEN(name) &&
67 memcmp(ZSTR_VAL(op_array->vars[i]), ZSTR_VAL(name), ZSTR_LEN(name)) == 0)) {
68 return (int)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, i);
69 }
70 i++;
71 }
72 i = op_array->last_var;
73 op_array->last_var++;
74 op_array->vars = erealloc(op_array->vars, op_array->last_var * sizeof(zend_string*));
75 op_array->vars[i] = zend_string_dup(name, 0);
76
77
78 {
79 zend_op *opline = op_array->opcodes;
80 zend_op *end = opline + op_array->last;
81 while (opline < end) {
82 if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
83 opline->op1.var += sizeof(zval);
84 }
85 if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
86 opline->op2.var += sizeof(zval);
87 }
88 if (opline->result_type & (IS_TMP_VAR|IS_VAR)) {
89 opline->result.var += sizeof(zval);
90 }
91 if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS ||
92 opline->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS ||
93 opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
94 opline->extended_value += sizeof(zval);
95 }
96 opline++;
97 }
98 }
99
100 return (int)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, i);
101 }
102
103 int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv)
104 {
105 int i = op_array->last_literal;
106 op_array->last_literal++;
107 op_array->literals = (zval*)erealloc(op_array->literals, op_array->last_literal * sizeof(zval));
108 ZVAL_COPY_VALUE(&op_array->literals[i], zv);
109 Z_CACHE_SLOT(op_array->literals[i]) = -1;
110 return i;
111 }
112
113 static inline int zend_optimizer_add_literal_string(zend_op_array *op_array, zend_string *str) {
114 zval zv;
115 ZVAL_STR(&zv, str);
116 zend_string_hash_val(str);
117 return zend_optimizer_add_literal(op_array, &zv);
118 }
119
120 int zend_optimizer_is_disabled_func(const char *name, size_t len) {
121 zend_function *fbc = (zend_function *)zend_hash_str_find_ptr(EG(function_table), name, len);
122
123 return (fbc && fbc->type == ZEND_INTERNAL_FUNCTION &&
124 fbc->internal_function.handler == ZEND_FN(display_disabled_function));
125 }
126
127 static inline void drop_leading_backslash(zval *val) {
128 if (Z_STRVAL_P(val)[0] == '\\') {
129 zend_string *str = zend_string_init(Z_STRVAL_P(val) + 1, Z_STRLEN_P(val) - 1, 0);
130 zval_dtor(val);
131 ZVAL_STR(val, str);
132 }
133 }
134
135 static inline void alloc_cache_slots_op1(zend_op_array *op_array, zend_op *opline, uint32_t num) {
136 Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->cache_size;
137 op_array->cache_size += num * sizeof(void *);
138 }
139 static inline void alloc_cache_slots_op2(zend_op_array *op_array, zend_op *opline, uint32_t num) {
140 Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
141 op_array->cache_size += num * sizeof(void *);
142 }
143
144 #define REQUIRES_STRING(val) do { \
145 if (Z_TYPE_P(val) != IS_STRING) { \
146 zval_dtor(val); \
147 return 0; \
148 } \
149 } while (0)
150
151 #define TO_STRING_NOWARN(val) do { \
152 if (Z_TYPE_P(val) >= IS_ARRAY) { \
153 zval_dtor(val); \
154 return 0; \
155 } \
156 convert_to_string(val); \
157 } while (0)
158
159 int zend_optimizer_update_op1_const(zend_op_array *op_array,
160 zend_op *opline,
161 zval *val)
162 {
163 switch (opline->opcode) {
164 case ZEND_FREE:
165 MAKE_NOP(opline);
166 zval_dtor(val);
167 return 1;
168 case ZEND_INIT_STATIC_METHOD_CALL:
169 case ZEND_CATCH:
170 case ZEND_FETCH_CONSTANT:
171 case ZEND_DEFINED:
172 case ZEND_NEW:
173 REQUIRES_STRING(val);
174 drop_leading_backslash(val);
175 opline->op1.constant = zend_optimizer_add_literal(op_array, val);
176 alloc_cache_slots_op1(op_array, opline, 1);
177 zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
178 break;
179 case ZEND_FETCH_R:
180 case ZEND_FETCH_W:
181 case ZEND_FETCH_RW:
182 case ZEND_FETCH_IS:
183 case ZEND_FETCH_UNSET:
184 case ZEND_FETCH_FUNC_ARG:
185 TO_STRING_NOWARN(val);
186 opline->op1.constant = zend_optimizer_add_literal(op_array, val);
187 if (opline->extended_value == ZEND_FETCH_STATIC_MEMBER) {
188 alloc_cache_slots_op1(op_array, opline, 2);
189 }
190 break;
191 case ZEND_CONCAT:
192 case ZEND_FAST_CONCAT:
193 TO_STRING_NOWARN(val);
194
195 default:
196 opline->op1.constant = zend_optimizer_add_literal(op_array, val);
197 break;
198 }
199
200 ZEND_OP1_TYPE(opline) = IS_CONST;
201 if (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
202 zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
203 }
204 return 1;
205 }
206
207 int zend_optimizer_update_op2_const(zend_op_array *op_array,
208 zend_op *opline,
209 zval *val)
210 {
211 switch (opline->opcode) {
212 case ZEND_ASSIGN_REF:
213 zval_dtor(val);
214 return 0;
215 case ZEND_FETCH_R:
216 case ZEND_FETCH_W:
217 case ZEND_FETCH_RW:
218 case ZEND_FETCH_IS:
219 case ZEND_FETCH_UNSET:
220 case ZEND_FETCH_FUNC_ARG:
221 case ZEND_FETCH_CLASS:
222 case ZEND_INIT_FCALL_BY_NAME:
223
224 case ZEND_UNSET_VAR:
225 case ZEND_ISSET_ISEMPTY_VAR:
226 case ZEND_ADD_INTERFACE:
227 case ZEND_ADD_TRAIT:
228 case ZEND_INSTANCEOF:
229 REQUIRES_STRING(val);
230 drop_leading_backslash(val);
231 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
232 zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
233 alloc_cache_slots_op2(op_array, opline, 1);
234 break;
235 case ZEND_INIT_FCALL:
236 REQUIRES_STRING(val);
237 zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
238 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
239 alloc_cache_slots_op2(op_array, opline, 1);
240 break;
241 case ZEND_INIT_DYNAMIC_CALL:
242 if (Z_TYPE_P(val) == IS_STRING) {
243 if (zend_memrchr(Z_STRVAL_P(val), ':', Z_STRLEN_P(val))) {
244 zval_dtor(val);
245 return 0;
246 }
247
248 opline->opcode = ZEND_INIT_FCALL_BY_NAME;
249 drop_leading_backslash(val);
250 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
251 zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
252 alloc_cache_slots_op2(op_array, opline, 1);
253 } else {
254 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
255 }
256 break;
257 case ZEND_INIT_METHOD_CALL:
258 case ZEND_INIT_STATIC_METHOD_CALL:
259 REQUIRES_STRING(val);
260 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
261 zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
262 alloc_cache_slots_op2(op_array, opline, 2);
263 break;
264
265 case ZEND_ASSIGN_OBJ:
266 case ZEND_FETCH_OBJ_R:
267 case ZEND_FETCH_OBJ_W:
268 case ZEND_FETCH_OBJ_RW:
269 case ZEND_FETCH_OBJ_IS:
270 case ZEND_FETCH_OBJ_UNSET:
271 case ZEND_FETCH_OBJ_FUNC_ARG:
272 case ZEND_UNSET_OBJ:
273 case ZEND_PRE_INC_OBJ:
274 case ZEND_PRE_DEC_OBJ:
275 case ZEND_POST_INC_OBJ:
276 case ZEND_POST_DEC_OBJ:
277 case ZEND_ISSET_ISEMPTY_PROP_OBJ:
278 TO_STRING_NOWARN(val);
279 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
280 alloc_cache_slots_op2(op_array, opline, 2);
281 break;
282 case ZEND_ASSIGN_ADD:
283 case ZEND_ASSIGN_SUB:
284 case ZEND_ASSIGN_MUL:
285 case ZEND_ASSIGN_DIV:
286 case ZEND_ASSIGN_POW:
287 case ZEND_ASSIGN_MOD:
288 case ZEND_ASSIGN_SL:
289 case ZEND_ASSIGN_SR:
290 case ZEND_ASSIGN_CONCAT:
291 case ZEND_ASSIGN_BW_OR:
292 case ZEND_ASSIGN_BW_AND:
293 case ZEND_ASSIGN_BW_XOR:
294 if (opline->extended_value == ZEND_ASSIGN_OBJ) {
295 TO_STRING_NOWARN(val);
296 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
297 alloc_cache_slots_op2(op_array, opline, 2);
298 } else {
299 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
300 }
301 break;
302 case ZEND_OP_DATA:
303 if ((opline-1)->opcode != ZEND_ASSIGN_DIM &&
304 ((opline-1)->extended_value != ZEND_ASSIGN_DIM ||
305 ((opline-1)->opcode != ZEND_ASSIGN_ADD &&
306 (opline-1)->opcode != ZEND_ASSIGN_SUB &&
307 (opline-1)->opcode != ZEND_ASSIGN_MUL &&
308 (opline-1)->opcode != ZEND_ASSIGN_DIV &&
309 (opline-1)->opcode != ZEND_ASSIGN_POW &&
310 (opline-1)->opcode != ZEND_ASSIGN_MOD &&
311 (opline-1)->opcode != ZEND_ASSIGN_SL &&
312 (opline-1)->opcode != ZEND_ASSIGN_SR &&
313 (opline-1)->opcode != ZEND_ASSIGN_CONCAT &&
314 (opline-1)->opcode != ZEND_ASSIGN_BW_OR &&
315 (opline-1)->opcode != ZEND_ASSIGN_BW_AND &&
316 (opline-1)->opcode != ZEND_ASSIGN_BW_XOR))
317 ) {
318 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
319 break;
320 }
321
322 case ZEND_ISSET_ISEMPTY_DIM_OBJ:
323 case ZEND_ADD_ARRAY_ELEMENT:
324 case ZEND_INIT_ARRAY:
325 case ZEND_ASSIGN_DIM:
326 case ZEND_UNSET_DIM:
327 case ZEND_FETCH_DIM_R:
328 case ZEND_FETCH_DIM_W:
329 case ZEND_FETCH_DIM_RW:
330 case ZEND_FETCH_DIM_IS:
331 case ZEND_FETCH_DIM_FUNC_ARG:
332 case ZEND_FETCH_DIM_UNSET:
333 case ZEND_FETCH_LIST:
334 if (Z_TYPE_P(val) == IS_STRING) {
335 zend_ulong index;
336 if (ZEND_HANDLE_NUMERIC(Z_STR_P(val), index)) {
337 zval_dtor(val);
338 ZVAL_LONG(val, index);
339 }
340 }
341 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
342 break;
343 case ZEND_ROPE_INIT:
344 case ZEND_ROPE_ADD:
345 case ZEND_ROPE_END:
346 case ZEND_CONCAT:
347 case ZEND_FAST_CONCAT:
348 TO_STRING_NOWARN(val);
349
350 default:
351 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
352 break;
353 }
354
355 ZEND_OP2_TYPE(opline) = IS_CONST;
356 if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
357 zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline)));
358 }
359 return 1;
360 }
361
362 int zend_optimizer_replace_by_const(zend_op_array *op_array,
363 zend_op *opline,
364 zend_uchar type,
365 uint32_t var,
366 zval *val)
367 {
368 zend_op *end = op_array->opcodes + op_array->last;
369
370 while (opline < end) {
371 if (ZEND_OP1_TYPE(opline) == type &&
372 ZEND_OP1(opline).var == var) {
373 switch (opline->opcode) {
374 case ZEND_FETCH_DIM_W:
375 case ZEND_FETCH_DIM_RW:
376 case ZEND_FETCH_DIM_FUNC_ARG:
377 case ZEND_FETCH_DIM_UNSET:
378 case ZEND_ASSIGN_DIM:
379 case ZEND_SEPARATE:
380 case ZEND_RETURN_BY_REF:
381 zval_dtor(val);
382 return 0;
383 case ZEND_SEND_VAR:
384 opline->extended_value = 0;
385 opline->opcode = ZEND_SEND_VAL;
386 break;
387 case ZEND_SEND_VAR_EX:
388 opline->extended_value = 0;
389 opline->opcode = ZEND_SEND_VAL_EX;
390 break;
391 case ZEND_SEND_VAR_NO_REF:
392 if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) {
393 if (opline->extended_value & ZEND_ARG_SEND_BY_REF) {
394 zval_dtor(val);
395 return 0;
396 }
397 opline->extended_value = 0;
398 opline->opcode = ZEND_SEND_VAL_EX;
399 } else {
400 opline->extended_value = 0;
401 opline->opcode = ZEND_SEND_VAL;
402 }
403 break;
404 case ZEND_SEND_USER:
405 opline->opcode = ZEND_SEND_VAL_EX;
406 break;
407
408
409
410
411
412
413 case ZEND_FREE:
414 case ZEND_CASE: {
415 zend_op *m, *n;
416 int brk = op_array->last_brk_cont;
417 zend_bool in_switch = 0;
418 while (brk--) {
419 if (op_array->brk_cont_array[brk].start <= (opline - op_array->opcodes) &&
420 op_array->brk_cont_array[brk].brk > (opline - op_array->opcodes)) {
421 in_switch = 1;
422 break;
423 }
424 }
425
426 if (!in_switch) {
427 ZEND_ASSERT(opline->opcode == ZEND_FREE);
428 MAKE_NOP(opline);
429 zval_dtor(val);
430 return 1;
431 }
432
433 m = opline;
434 n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1;
435 while (m < n) {
436 if (ZEND_OP1_TYPE(m) == type &&
437 ZEND_OP1(m).var == var) {
438 if (m->opcode == ZEND_CASE) {
439 zval old_val;
440 ZVAL_COPY_VALUE(&old_val, val);
441 zval_copy_ctor(val);
442 zend_optimizer_update_op1_const(op_array, m, val);
443 ZVAL_COPY_VALUE(val, &old_val);
444 } else if (m->opcode == ZEND_FREE) {
445 MAKE_NOP(m);
446 } else {
447 ZEND_ASSERT(0);
448 }
449 }
450 m++;
451 }
452 zval_dtor(val);
453 return 1;
454 }
455 case ZEND_VERIFY_RETURN_TYPE: {
456 zend_arg_info *ret_info = op_array->arg_info - 1;
457 ZEND_ASSERT((opline + 1)->opcode == ZEND_RETURN || (opline + 1)->opcode == ZEND_RETURN_BY_REF);
458 if (ret_info->class_name
459 || ret_info->type_hint == IS_CALLABLE
460 || !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(val))
461 || (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
462 zval_dtor(val);
463 return 0;
464 }
465 MAKE_NOP(opline);
466 zend_optimizer_update_op1_const(op_array, opline + 1, val);
467 return 1;
468 }
469 default:
470 break;
471 }
472 return zend_optimizer_update_op1_const(op_array, opline, val);
473 }
474
475 if (ZEND_OP2_TYPE(opline) == type &&
476 ZEND_OP2(opline).var == var) {
477 return zend_optimizer_update_op2_const(op_array, opline, val);
478 }
479 opline++;
480 }
481
482 return 1;
483 }
484
485 static void zend_optimize(zend_op_array *op_array,
486 zend_optimizer_ctx *ctx)
487 {
488 if (op_array->type == ZEND_EVAL_CODE) {
489 return;
490 }
491
492
493
494
495
496
497
498 if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
499 zend_optimizer_pass1(op_array, ctx);
500 }
501
502
503
504
505
506
507
508 if (ZEND_OPTIMIZER_PASS_2 & OPTIMIZATION_LEVEL) {
509 zend_optimizer_pass2(op_array);
510 }
511
512
513
514
515
516
517 if (ZEND_OPTIMIZER_PASS_3 & OPTIMIZATION_LEVEL) {
518 zend_optimizer_pass3(op_array);
519 }
520
521
522
523
524 if (ZEND_OPTIMIZER_PASS_4 & OPTIMIZATION_LEVEL) {
525 optimize_func_calls(op_array, ctx);
526 }
527
528
529
530
531 if (ZEND_OPTIMIZER_PASS_5 & OPTIMIZATION_LEVEL) {
532 optimize_cfg(op_array, ctx);
533 }
534
535
536
537
538 if (ZEND_OPTIMIZER_PASS_9 & OPTIMIZATION_LEVEL) {
539 optimize_temporary_variables(op_array, ctx);
540 }
541
542
543
544
545 if (((ZEND_OPTIMIZER_PASS_10|ZEND_OPTIMIZER_PASS_5) & OPTIMIZATION_LEVEL) == ZEND_OPTIMIZER_PASS_10) {
546 zend_optimizer_nop_removal(op_array);
547 }
548
549
550
551
552 if (ZEND_OPTIMIZER_PASS_11 & OPTIMIZATION_LEVEL) {
553 zend_optimizer_compact_literals(op_array, ctx);
554 }
555 }
556
557 static void zend_accel_optimize(zend_op_array *op_array,
558 zend_optimizer_ctx *ctx)
559 {
560 zend_op *opline, *end;
561
562
563 opline = op_array->opcodes;
564 end = opline + op_array->last;
565 while (opline < end) {
566 if (opline->op1_type == IS_CONST) {
567 ZEND_PASS_TWO_UNDO_CONSTANT(op_array, opline->op1);
568 }
569 if (opline->op2_type == IS_CONST) {
570 ZEND_PASS_TWO_UNDO_CONSTANT(op_array, opline->op2);
571 }
572 switch (opline->opcode) {
573 case ZEND_JMP:
574 case ZEND_FAST_CALL:
575 case ZEND_DECLARE_ANON_CLASS:
576 case ZEND_DECLARE_ANON_INHERITED_CLASS:
577 ZEND_PASS_TWO_UNDO_JMP_TARGET(op_array, opline, ZEND_OP1(opline));
578 break;
579 case ZEND_JMPZNZ:
580
581 opline->extended_value = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
582
583 case ZEND_JMPZ:
584 case ZEND_JMPNZ:
585 case ZEND_JMPZ_EX:
586 case ZEND_JMPNZ_EX:
587 case ZEND_JMP_SET:
588 case ZEND_COALESCE:
589 case ZEND_NEW:
590 case ZEND_FE_RESET_R:
591 case ZEND_FE_RESET_RW:
592 case ZEND_ASSERT_CHECK:
593 ZEND_PASS_TWO_UNDO_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
594 break;
595 case ZEND_FE_FETCH_R:
596 case ZEND_FE_FETCH_RW:
597 opline->extended_value = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
598 break;
599 }
600 opline++;
601 }
602
603
604 zend_optimize(op_array, ctx);
605
606
607 opline = op_array->opcodes;
608 end = opline + op_array->last;
609 while (opline < end) {
610 if (opline->op1_type == IS_CONST) {
611 ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op1);
612 }
613 if (opline->op2_type == IS_CONST) {
614 ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
615 }
616 switch (opline->opcode) {
617 case ZEND_JMP:
618 case ZEND_FAST_CALL:
619 case ZEND_DECLARE_ANON_CLASS:
620 case ZEND_DECLARE_ANON_INHERITED_CLASS:
621 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, ZEND_OP1(opline));
622 break;
623 case ZEND_JMPZNZ:
624
625 opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
626
627 case ZEND_JMPZ:
628 case ZEND_JMPNZ:
629 case ZEND_JMPZ_EX:
630 case ZEND_JMPNZ_EX:
631 case ZEND_JMP_SET:
632 case ZEND_COALESCE:
633 case ZEND_NEW:
634 case ZEND_FE_RESET_R:
635 case ZEND_FE_RESET_RW:
636 case ZEND_ASSERT_CHECK:
637 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
638 break;
639 case ZEND_FE_FETCH_R:
640 case ZEND_FE_FETCH_RW:
641 opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
642 break;
643 }
644 ZEND_VM_SET_OPCODE_HANDLER(opline);
645 opline++;
646 }
647 }
648
649 static void zend_accel_adjust_fcall_stack_size(zend_op_array *op_array, zend_optimizer_ctx *ctx)
650 {
651 zend_function *func;
652 zend_op *opline, *end;
653
654 opline = op_array->opcodes;
655 end = opline + op_array->last;
656 while (opline < end) {
657 if (opline->opcode == ZEND_INIT_FCALL) {
658 func = zend_hash_find_ptr(
659 &ctx->script->function_table,
660 Z_STR_P(RT_CONSTANT(op_array, opline->op2)));
661 if (func) {
662 opline->op1.num = zend_vm_calc_used_stack(opline->extended_value, func);
663 }
664 }
665 opline++;
666 }
667 }
668
669 int zend_accel_script_optimize(zend_persistent_script *script)
670 {
671 uint idx, j;
672 Bucket *p, *q;
673 zend_class_entry *ce;
674 zend_op_array *op_array;
675 zend_optimizer_ctx ctx;
676
677 ctx.arena = zend_arena_create(64 * 1024);
678 ctx.script = script;
679 ctx.constants = NULL;
680
681 zend_accel_optimize(&script->main_op_array, &ctx);
682
683 for (idx = 0; idx < script->function_table.nNumUsed; idx++) {
684 p = script->function_table.arData + idx;
685 if (Z_TYPE(p->val) == IS_UNDEF) continue;
686 op_array = (zend_op_array*)Z_PTR(p->val);
687 zend_accel_optimize(op_array, &ctx);
688 }
689
690 for (idx = 0; idx < script->class_table.nNumUsed; idx++) {
691 p = script->class_table.arData + idx;
692 if (Z_TYPE(p->val) == IS_UNDEF) continue;
693 ce = (zend_class_entry*)Z_PTR(p->val);
694 for (j = 0; j < ce->function_table.nNumUsed; j++) {
695 q = ce->function_table.arData + j;
696 if (Z_TYPE(q->val) == IS_UNDEF) continue;
697 op_array = (zend_op_array*)Z_PTR(q->val);
698 if (op_array->scope == ce) {
699 zend_accel_optimize(op_array, &ctx);
700 } else if (op_array->type == ZEND_USER_FUNCTION) {
701 zend_op_array *orig_op_array;
702 if ((orig_op_array = zend_hash_find_ptr(&op_array->scope->function_table, q->key)) != NULL) {
703 HashTable *ht = op_array->static_variables;
704 *op_array = *orig_op_array;
705 op_array->static_variables = ht;
706 }
707 }
708 }
709 }
710
711 if (ZEND_OPTIMIZER_PASS_12 & OPTIMIZATION_LEVEL) {
712 zend_accel_adjust_fcall_stack_size(&script->main_op_array, &ctx);
713
714 for (idx = 0; idx < script->function_table.nNumUsed; idx++) {
715 p = script->function_table.arData + idx;
716 if (Z_TYPE(p->val) == IS_UNDEF) continue;
717 op_array = (zend_op_array*)Z_PTR(p->val);
718 zend_accel_adjust_fcall_stack_size(op_array, &ctx);
719 }
720
721 for (idx = 0; idx < script->class_table.nNumUsed; idx++) {
722 p = script->class_table.arData + idx;
723 if (Z_TYPE(p->val) == IS_UNDEF) continue;
724 ce = (zend_class_entry*)Z_PTR(p->val);
725 for (j = 0; j < ce->function_table.nNumUsed; j++) {
726 q = ce->function_table.arData + j;
727 if (Z_TYPE(q->val) == IS_UNDEF) continue;
728 op_array = (zend_op_array*)Z_PTR(q->val);
729 if (op_array->scope == ce) {
730 zend_accel_adjust_fcall_stack_size(op_array, &ctx);
731 } else if (op_array->type == ZEND_USER_FUNCTION) {
732 zend_op_array *orig_op_array;
733 if ((orig_op_array = zend_hash_find_ptr(&op_array->scope->function_table, q->key)) != NULL) {
734 HashTable *ht = op_array->static_variables;
735 *op_array = *orig_op_array;
736 op_array->static_variables = ht;
737 }
738 }
739 }
740 }
741 }
742
743 if (ctx.constants) {
744 zend_hash_destroy(ctx.constants);
745 }
746 zend_arena_destroy(ctx.arena);
747
748 return 1;
749 }