This source file includes following definitions.
- zend_optimizer_get_persistent_constant
- print_block
- find_code_blocks
- replace_source
- del_source
- delete_code_block
- zend_access_path
- zend_rebuild_access_path
- strip_nop
- zend_optimize_block
- assemble_code_blocks
- zend_jmp_optimization
- zend_t_usage
- optimize_cfg
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 #include "zend_bitset.h"
30
31 #define DEBUG_BLOCKPASS 0
32
33
34 int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy)
35 {
36 zend_constant *c;
37 char *lookup_name;
38 int retval = 1;
39 ALLOCA_FLAG(use_heap);
40
41 if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) {
42 lookup_name = DO_ALLOCA(ZSTR_LEN(name) + 1);
43 memcpy(lookup_name, ZSTR_VAL(name), ZSTR_LEN(name) + 1);
44 zend_str_tolower(lookup_name, ZSTR_LEN(name));
45
46 if ((c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, ZSTR_LEN(name))) != NULL) {
47 if (!(c->flags & CONST_CT_SUBST) || (c->flags & CONST_CS)) {
48 retval = 0;
49 }
50 } else {
51 retval = 0;
52 }
53 FREE_ALLOCA(lookup_name);
54 }
55
56 if (retval) {
57 if (c->flags & CONST_PERSISTENT) {
58 ZVAL_COPY_VALUE(result, &c->value);
59 if (copy) {
60 zval_copy_ctor(result);
61 }
62 } else {
63 retval = 0;
64 }
65 }
66
67 return retval;
68 }
69
70 #if DEBUG_BLOCKPASS
71 # define BLOCK_REF(b) b?op_array->opcodes-b->start_opline:-1
72
73 static inline void print_block(zend_code_block *block, zend_op *opcodes, char *txt)
74 {
75 fprintf(stderr, "%sBlock: %d-%d (%d)", txt, block->start_opline - opcodes, block->start_opline - opcodes + block->len - 1, block->len);
76 if (!block->access) {
77 fprintf(stderr, " unused");
78 }
79 if (block->op1_to) {
80 fprintf(stderr, " 1: %d", block->op1_to->start_opline - opcodes);
81 }
82 if (block->op2_to) {
83 fprintf(stderr, " 2: %d", block->op2_to->start_opline - opcodes);
84 }
85 if (block->ext_to) {
86 fprintf(stderr, " e: %d", block->ext_to->start_opline - opcodes);
87 }
88 if (block->follow_to) {
89 fprintf(stderr, " f: %d", block->follow_to->start_opline - opcodes);
90 }
91
92 if (block->sources) {
93 zend_block_source *bs = block->sources;
94 fprintf(stderr, " s:");
95 while (bs) {
96 fprintf(stderr, " %d", bs->from->start_opline - opcodes);
97 bs = bs->next;
98 }
99 }
100
101 fprintf(stderr, "\n");
102 fflush(stderr);
103 }
104 #else
105 #define print_block(a,b,c)
106 #endif
107
108 #define START_BLOCK_OP(opno) blocks[opno].start_opline = &op_array->opcodes[opno]; blocks[opno].start_opline_no = opno; blocks[opno].access = 1
109
110
111
112
113 static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimizer_ctx *ctx)
114 {
115 zend_op *opline;
116 zend_op *end = op_array->opcodes + op_array->last;
117 zend_code_block *blocks, *cur_block;
118 uint32_t opno = 0;
119
120 memset(cfg, 0, sizeof(zend_cfg));
121 blocks = cfg->blocks = zend_arena_calloc(&ctx->arena, op_array->last + 2, sizeof(zend_code_block));
122 opline = op_array->opcodes;
123 blocks[0].start_opline = opline;
124 blocks[0].start_opline_no = 0;
125 while (opline < end) {
126 switch((unsigned)opline->opcode) {
127 case ZEND_FAST_CALL:
128 START_BLOCK_OP(ZEND_OP1(opline).opline_num);
129 if (opline->extended_value) {
130 START_BLOCK_OP(ZEND_OP2(opline).opline_num);
131 }
132 START_BLOCK_OP(opno + 1);
133 break;
134 case ZEND_FAST_RET:
135 if (opline->extended_value) {
136 START_BLOCK_OP(ZEND_OP2(opline).opline_num);
137 }
138 START_BLOCK_OP(opno + 1);
139 break;
140 case ZEND_JMP:
141 case ZEND_DECLARE_ANON_CLASS:
142 case ZEND_DECLARE_ANON_INHERITED_CLASS:
143 START_BLOCK_OP(ZEND_OP1(opline).opline_num);
144
145 case ZEND_RETURN:
146 case ZEND_RETURN_BY_REF:
147 case ZEND_GENERATOR_RETURN:
148 case ZEND_EXIT:
149 case ZEND_THROW:
150
151 START_BLOCK_OP(opno + 1);
152 break;
153
154
155 case ZEND_CATCH:
156 START_BLOCK_OP(opline->extended_value);
157 START_BLOCK_OP(opno + 1);
158 break;
159 case ZEND_JMPZNZ:
160 START_BLOCK_OP(opline->extended_value);
161 case ZEND_JMPZ:
162 case ZEND_JMPNZ:
163 case ZEND_JMPZ_EX:
164 case ZEND_JMPNZ_EX:
165 case ZEND_FE_RESET_R:
166 case ZEND_FE_RESET_RW:
167 case ZEND_NEW:
168 case ZEND_JMP_SET:
169 case ZEND_COALESCE:
170 case ZEND_ASSERT_CHECK:
171 START_BLOCK_OP(ZEND_OP2(opline).opline_num);
172 START_BLOCK_OP(opno + 1);
173 break;
174 case ZEND_FE_FETCH_R:
175 case ZEND_FE_FETCH_RW:
176 START_BLOCK_OP(opline->extended_value);
177 START_BLOCK_OP(opno + 1);
178 break;
179 }
180 opno++;
181 opline++;
182 }
183
184
185 if (op_array->last_try_catch) {
186 int i;
187 cfg->try = zend_arena_calloc(&ctx->arena, op_array->last_try_catch, sizeof(zend_code_block *));
188 cfg->catch = zend_arena_calloc(&ctx->arena, op_array->last_try_catch, sizeof(zend_code_block *));
189 for (i = 0; i< op_array->last_try_catch; i++) {
190 cfg->try[i] = &blocks[op_array->try_catch_array[i].try_op];
191 cfg->catch[i] = &blocks[op_array->try_catch_array[i].catch_op];
192 START_BLOCK_OP(op_array->try_catch_array[i].try_op);
193 START_BLOCK_OP(op_array->try_catch_array[i].catch_op);
194 blocks[op_array->try_catch_array[i].try_op].protected = 1;
195 }
196 }
197
198
199
200 if (op_array->last_brk_cont) {
201 int i, j;
202
203 j = 0;
204 for (i = 0; i< op_array->last_brk_cont; i++) {
205 if (op_array->brk_cont_array[i].start >= 0 &&
206 (op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
207 op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
208 op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_ROPE_END ||
209 op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
210 int parent = op_array->brk_cont_array[i].parent;
211
212 while (parent >= 0 &&
213 op_array->brk_cont_array[parent].start < 0 &&
214 (op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FREE ||
215 op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FE_FREE ||
216 op_array->opcodes[op_array->brk_cont_array[i].brk].opcode != ZEND_ROPE_END ||
217 op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_END_SILENCE)) {
218 parent = op_array->brk_cont_array[parent].parent;
219 }
220 op_array->brk_cont_array[i].parent = parent;
221 j++;
222 }
223 }
224 if (j) {
225 cfg->loop_start = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *));
226 cfg->loop_cont = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *));
227 cfg->loop_brk = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *));
228 j = 0;
229 for (i = 0; i< op_array->last_brk_cont; i++) {
230 if (op_array->brk_cont_array[i].start >= 0 &&
231 (op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
232 op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
233 op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_ROPE_END ||
234 op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
235 if (i != j) {
236 op_array->brk_cont_array[j] = op_array->brk_cont_array[i];
237 }
238 cfg->loop_start[j] = &blocks[op_array->brk_cont_array[j].start];
239 cfg->loop_cont[j] = &blocks[op_array->brk_cont_array[j].cont];
240 cfg->loop_brk[j] = &blocks[op_array->brk_cont_array[j].brk];
241 START_BLOCK_OP(op_array->brk_cont_array[j].start);
242 START_BLOCK_OP(op_array->brk_cont_array[j].cont);
243 START_BLOCK_OP(op_array->brk_cont_array[j].brk);
244 blocks[op_array->brk_cont_array[j].start].protected = 1;
245 blocks[op_array->brk_cont_array[j].brk].protected = 1;
246 j++;
247 }
248 }
249 op_array->last_brk_cont = j;
250 } else {
251 efree(op_array->brk_cont_array);
252 op_array->brk_cont_array = NULL;
253 op_array->last_brk_cont = 0;
254 }
255 }
256
257
258 cur_block = blocks;
259 for (opno = 1; opno < op_array->last; opno++) {
260 if (blocks[opno].start_opline) {
261
262 cur_block->len = blocks[opno].start_opline - cur_block->start_opline;
263 cur_block->next = &blocks[opno];
264
265 opline = blocks[opno].start_opline - 1;
266 if (opline->opcode == ZEND_OP_DATA) {
267 opline--;
268 }
269 switch((unsigned)opline->opcode) {
270 case ZEND_RETURN:
271 case ZEND_RETURN_BY_REF:
272 case ZEND_GENERATOR_RETURN:
273 case ZEND_EXIT:
274 case ZEND_THROW:
275 break;
276 case ZEND_FAST_CALL:
277 if (opline->extended_value) {
278 cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
279 }
280 cur_block->op1_to = &blocks[ZEND_OP1(opline).opline_num];
281 break;
282 case ZEND_FAST_RET:
283 if (opline->extended_value) {
284 cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
285 }
286 break;
287 case ZEND_JMP:
288 cur_block->op1_to = &blocks[ZEND_OP1(opline).opline_num];
289 break;
290 case ZEND_DECLARE_ANON_CLASS:
291 case ZEND_DECLARE_ANON_INHERITED_CLASS:
292 cur_block->op1_to = &blocks[ZEND_OP1(opline).opline_num];
293 cur_block->follow_to = &blocks[opno];
294 break;
295 case ZEND_JMPZNZ:
296 cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
297 cur_block->ext_to = &blocks[opline->extended_value];
298 break;
299 case ZEND_CATCH:
300 cur_block->ext_to = &blocks[opline->extended_value];
301 cur_block->follow_to = &blocks[opno];
302 break;
303 case ZEND_FE_FETCH_R:
304 case ZEND_FE_FETCH_RW:
305 cur_block->ext_to = &blocks[opline->extended_value];
306 cur_block->follow_to = &blocks[opno];
307 break;
308 case ZEND_JMPZ:
309 case ZEND_JMPNZ:
310 case ZEND_JMPZ_EX:
311 case ZEND_JMPNZ_EX:
312 case ZEND_FE_RESET_R:
313 case ZEND_FE_RESET_RW:
314 case ZEND_NEW:
315 case ZEND_JMP_SET:
316 case ZEND_COALESCE:
317 case ZEND_ASSERT_CHECK:
318 cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
319
320 default:
321
322 cur_block->follow_to = &blocks[opno];
323 break;
324 }
325 print_block(cur_block, op_array->opcodes, "");
326 cur_block = cur_block->next;
327 }
328 }
329 cur_block->len = end - cur_block->start_opline;
330 cur_block->next = &blocks[op_array->last + 1];
331 print_block(cur_block, op_array->opcodes, "");
332
333 return 1;
334 }
335
336
337
338 #define ADD_SOURCE(fromb, tob) { \
339 zend_block_source *__s = tob->sources; \
340 while (__s && __s->from != fromb) __s = __s->next; \
341 if (__s == NULL) { \
342 zend_block_source *__t = zend_arena_alloc(&ctx->arena, sizeof(zend_block_source)); \
343 __t->next = tob->sources; \
344 tob->sources = __t; \
345 __t->from = fromb; \
346 } \
347 }
348
349 #define DEL_SOURCE(cs) do { \
350 *(cs) = (*(cs))->next; \
351 } while (0)
352
353
354 static inline void replace_source(zend_block_source *list, zend_code_block *old, zend_code_block *new)
355 {
356
357 zend_block_source **cs;
358 int found = 0;
359
360 for (cs = &list; *cs; cs = &((*cs)->next)) {
361 if ((*cs)->from == new) {
362 if (found) {
363 DEL_SOURCE(cs);
364 } else {
365 found = 1;
366 }
367 }
368
369 if ((*cs)->from == old) {
370 if (found) {
371 DEL_SOURCE(cs);
372 } else {
373 (*cs)->from = new;
374 found = 1;
375 }
376 }
377 }
378 }
379
380 static inline void del_source(zend_code_block *from, zend_code_block *to)
381 {
382
383 zend_block_source **cs = &to->sources;
384
385 if (to->sources == NULL) {
386 to->access = 0;
387 return;
388 }
389
390 if (from == to) {
391 return;
392 }
393
394 while (*cs) {
395 if ((*cs)->from == from) {
396 DEL_SOURCE(cs);
397 break;
398 }
399 cs = &((*cs)->next);
400 }
401
402 if (to->sources == NULL) {
403
404 to->access = 0;
405 return;
406 }
407
408 if (!to->protected && to->sources->next == NULL) {
409
410 zend_code_block *from_block = to->sources->from;
411
412 if (from_block->access && from_block->follow_to == to &&
413 from_block->op1_to == NULL &&
414 from_block->op2_to == NULL &&
415 from_block->ext_to == NULL) {
416
417 zend_op *new_to = from_block->start_opline + from_block->len;
418 if (new_to != to->start_opline) {
419
420 memmove(new_to, to->start_opline, sizeof(zend_op)*to->len);
421 }
422
423 from_block->len += to->len;
424
425 to->start_opline = NULL;
426 to->access = 0;
427 to->sources = NULL;
428 from_block->follow_to = to->follow_to;
429 if (to->op1_to) {
430 from_block->op1_to = to->op1_to;
431 replace_source(to->op1_to->sources, to, from_block);
432 }
433 if (to->op2_to) {
434 from_block->op2_to = to->op2_to;
435 replace_source(to->op2_to->sources, to, from_block);
436 }
437 if (to->ext_to) {
438 from_block->ext_to = to->ext_to;
439 replace_source(to->ext_to->sources, to, from_block);
440 }
441 if (to->follow_to) {
442 replace_source(to->follow_to->sources, to, from_block);
443 }
444
445 }
446 }
447 }
448
449 static void delete_code_block(zend_code_block *block, zend_optimizer_ctx *ctx)
450 {
451 if (block->protected) {
452 return;
453 }
454 if (block->follow_to) {
455 zend_block_source *bs = block->sources;
456 while (bs) {
457 zend_code_block *from_block = bs->from;
458 zend_code_block *to = block->follow_to;
459 if (from_block->op1_to == block) {
460 from_block->op1_to = to;
461 ADD_SOURCE(from_block, to);
462 }
463 if (from_block->op2_to == block) {
464 from_block->op2_to = to;
465 ADD_SOURCE(from_block, to);
466 }
467 if (from_block->ext_to == block) {
468 from_block->ext_to = to;
469 ADD_SOURCE(from_block, to);
470 }
471 if (from_block->follow_to == block) {
472 from_block->follow_to = to;
473 ADD_SOURCE(from_block, to);
474 }
475 bs = bs->next;
476 }
477 }
478 block->access = 0;
479 }
480
481 static void zend_access_path(zend_code_block *block, zend_optimizer_ctx *ctx)
482 {
483 if (block->access) {
484 return;
485 }
486
487 block->access = 1;
488 if (block->op1_to) {
489 zend_access_path(block->op1_to, ctx);
490 ADD_SOURCE(block, block->op1_to);
491 }
492 if (block->op2_to) {
493 zend_access_path(block->op2_to, ctx);
494 ADD_SOURCE(block, block->op2_to);
495 }
496 if (block->ext_to) {
497 zend_access_path(block->ext_to, ctx);
498 ADD_SOURCE(block, block->ext_to);
499 }
500 if (block->follow_to) {
501 zend_access_path(block->follow_to, ctx);
502 ADD_SOURCE(block, block->follow_to);
503 }
504 }
505
506
507 static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int find_start, zend_optimizer_ctx *ctx)
508 {
509 zend_code_block *blocks = cfg->blocks;
510 zend_code_block *start = find_start? NULL : blocks;
511 zend_code_block *b;
512
513
514 b = blocks;
515 while (b != NULL) {
516 if (!start && b->access) {
517 start = b;
518 }
519 b->access = 0;
520 b->sources = NULL;
521 b = b->next;
522 }
523
524
525 zend_access_path(start, ctx);
526
527
528 if (op_array->last_brk_cont) {
529 int i;
530 for (i=0; i< op_array->last_brk_cont; i++) {
531 zend_access_path(cfg->loop_start[i], ctx);
532 zend_access_path(cfg->loop_cont[i], ctx);
533 zend_access_path(cfg->loop_brk[i], ctx);
534 }
535 }
536
537
538 if (op_array->last_try_catch) {
539 int i;
540 for (i=0; i< op_array->last_try_catch; i++) {
541 if (!cfg->catch[i]->access) {
542 zend_access_path(cfg->catch[i], ctx);
543 }
544 }
545 }
546 }
547
548
549
550 #define VAR_NUM_EX(op) VAR_NUM((op).var)
551
552 #define VAR_SOURCE(op) Tsource[VAR_NUM(op.var)]
553 #define SET_VAR_SOURCE(opline) Tsource[VAR_NUM(opline->result.var)] = opline
554
555 #define VAR_UNSET(op) do { if (op ## _type & (IS_TMP_VAR|IS_VAR)) {VAR_SOURCE(op) = NULL;}} while (0)
556
557 #define convert_to_string_safe(v) \
558 if (Z_TYPE_P((v)) == IS_NULL) { \
559 ZVAL_STRINGL((v), "", 0); \
560 } else { \
561 convert_to_string((v)); \
562 }
563
564 static void strip_nop(zend_code_block *block, zend_optimizer_ctx *ctx)
565 {
566 zend_op *opline = block->start_opline;
567 zend_op *end, *new_end;
568
569
570 while (block->len > 0 && block->start_opline->opcode == ZEND_NOP) {
571 if (block->len == 1) {
572
573 if (block->follow_to) {
574 delete_code_block(block, ctx);
575 }
576 return;
577 }
578 block->start_opline++;
579 block->start_opline_no++;
580 block->len--;
581 }
582
583
584 opline = new_end = block->start_opline;
585 end = opline + block->len;
586
587 while (opline < end) {
588 zend_op *src;
589 int len = 0;
590
591 while (opline < end && opline->opcode == ZEND_NOP) {
592 opline++;
593 }
594 src = opline;
595
596 while (opline < end && opline->opcode != ZEND_NOP) {
597 opline++;
598 }
599 len = opline - src;
600
601
602 memmove(new_end, src, len*sizeof(zend_op));
603
604 new_end += len;
605 }
606 block->len = new_end - block->start_opline;
607 }
608
609 static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, zend_bitset used_ext, zend_cfg *cfg, zend_optimizer_ctx *ctx)
610 {
611 zend_op *opline = block->start_opline;
612 zend_op *end, *last_op = NULL;
613 zend_op **Tsource = cfg->Tsource;
614
615 print_block(block, op_array->opcodes, "Opt ");
616
617
618 while (block->len > 0 && block->start_opline->opcode == ZEND_NOP) {
619 if (block->len == 1) {
620
621 if (block->follow_to) {
622 delete_code_block(block, ctx);
623 }
624 return;
625 }
626 block->start_opline++;
627 block->start_opline_no++;
628 block->len--;
629 }
630
631
632 memset(Tsource, 0, (op_array->last_var + op_array->T) * sizeof(zend_op *));
633 opline = block->start_opline;
634 end = opline + block->len;
635 while ((op_array->T) && (opline < end)) {
636
637 if ((ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
638 VAR_SOURCE(opline->op1) &&
639 VAR_SOURCE(opline->op1)->opcode == ZEND_QM_ASSIGN &&
640 ZEND_OP1_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST &&
641 opline->opcode != ZEND_CASE &&
642 opline->opcode != ZEND_FETCH_LIST &&
643 (opline->opcode != ZEND_FE_RESET_R || opline->opcode != ZEND_FE_RESET_RW) &&
644 opline->opcode != ZEND_FREE
645 ) {
646 znode_op op1 = opline->op1;
647 zend_op *src = VAR_SOURCE(op1);
648 zval c = ZEND_OP1_LITERAL(src);
649 zval_copy_ctor(&c);
650 if (zend_optimizer_update_op1_const(op_array, opline, &c)) {
651 VAR_SOURCE(op1) = NULL;
652 literal_dtor(&ZEND_OP1_LITERAL(src));
653 MAKE_NOP(src);
654 }
655 }
656
657
658 if ((ZEND_OP2_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
659 VAR_SOURCE(opline->op2) &&
660 VAR_SOURCE(opline->op2)->opcode == ZEND_QM_ASSIGN &&
661 ZEND_OP1_TYPE(VAR_SOURCE(opline->op2)) == IS_CONST) {
662 znode_op op2 = opline->op2;
663 zend_op *src = VAR_SOURCE(op2);
664 zval c = ZEND_OP1_LITERAL(src);
665 zval_copy_ctor(&c);
666 if (zend_optimizer_update_op2_const(op_array, opline, &c)) {
667 VAR_SOURCE(op2) = NULL;
668 literal_dtor(&ZEND_OP1_LITERAL(src));
669 MAKE_NOP(src);
670 }
671 }
672
673
674 if (opline->opcode == ZEND_ECHO &&
675 ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR) &&
676 VAR_SOURCE(opline->op1) &&
677 VAR_SOURCE(opline->op1)->opcode == ZEND_CAST &&
678 VAR_SOURCE(opline->op1)->extended_value == IS_STRING) {
679 zend_op *src = VAR_SOURCE(opline->op1);
680 COPY_NODE(opline->op1, src->op1);
681 MAKE_NOP(src);
682 }
683
684
685 if (opline->opcode == ZEND_FREE &&
686 ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
687 VAR_SOURCE(opline->op1)) {
688 zend_op *src = VAR_SOURCE(opline->op1);
689 if (src->opcode == ZEND_BOOL) {
690 if (ZEND_OP1_TYPE(src) == IS_CONST) {
691 literal_dtor(&ZEND_OP1_LITERAL(src));
692 }
693 MAKE_NOP(src);
694 MAKE_NOP(opline);
695 }
696 }
697
698 #if 0
699
700
701
702
703
704
705
706 if((ZEND_OP1_TYPE(opline) & IS_VAR) &&
707 VAR_SOURCE(opline->op1) && VAR_SOURCE(opline->op1)->opcode == ZEND_DO_CF_FCALL &&
708 VAR_SOURCE(opline->op1)->extended_value == 1) {
709 zend_op *fcall = VAR_SOURCE(opline->op1);
710 zend_op *sv = fcall-1;
711 if(sv >= block->start_opline && sv->opcode == ZEND_SEND_VAL &&
712 ZEND_OP1_TYPE(sv) == IS_CONST && Z_TYPE(OPLINE_OP1_LITERAL(sv)) == IS_STRING &&
713 Z_LVAL(OPLINE_OP2_LITERAL(sv)) == 1
714 ) {
715 zval *arg = &OPLINE_OP1_LITERAL(sv);
716 char *fname = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].function_name;
717 int flen = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].name_len;
718 if(flen == sizeof("defined")-1 && zend_binary_strcasecmp(fname, flen, "defined", sizeof("defined")-1) == 0) {
719 zval c;
720 if(zend_optimizer_get_persistent_constant(Z_STR_P(arg), &c, 0 ELS_CC) != 0) {
721 literal_dtor(arg);
722 MAKE_NOP(sv);
723 MAKE_NOP(fcall);
724 LITERAL_BOOL(opline->op1, 1);
725 ZEND_OP1_TYPE(opline) = IS_CONST;
726 }
727 } else if((flen == sizeof("function_exists")-1 && zend_binary_strcasecmp(fname, flen, "function_exists", sizeof("function_exists")-1) == 0) ||
728 (flen == sizeof("is_callable")-1 && zend_binary_strcasecmp(fname, flen, "is_callable", sizeof("is_callable")-1) == 0)
729 ) {
730 zend_function *function;
731 if((function = zend_hash_find_ptr(EG(function_table), Z_STR_P(arg))) != NULL) {
732 literal_dtor(arg);
733 MAKE_NOP(sv);
734 MAKE_NOP(fcall);
735 LITERAL_BOOL(opline->op1, 1);
736 ZEND_OP1_TYPE(opline) = IS_CONST;
737 }
738 } else if(flen == sizeof("constant")-1 && zend_binary_strcasecmp(fname, flen, "constant", sizeof("constant")-1) == 0) {
739 zval c;
740 if(zend_optimizer_get_persistent_constant(Z_STR_P(arg), &c, 1 ELS_CC) != 0) {
741 literal_dtor(arg);
742 MAKE_NOP(sv);
743 MAKE_NOP(fcall);
744 ZEND_OP1_LITERAL(opline) = zend_optimizer_add_literal(op_array, &c);
745
746 ZEND_OP1_TYPE(opline) = IS_CONST;
747 }
748 } else if(flen == sizeof("extension_loaded")-1 && zend_binary_strcasecmp(fname, flen, "extension_loaded", sizeof("extension_loaded")-1) == 0) {
749 if(zend_hash_exists(&module_registry, Z_STR_P(arg))) {
750 literal_dtor(arg);
751 MAKE_NOP(sv);
752 MAKE_NOP(fcall);
753 LITERAL_BOOL(opline->op1, 1);
754 ZEND_OP1_TYPE(opline) = IS_CONST;
755 }
756 }
757 }
758 }
759 #endif
760
761
762
763
764
765
766
767
768 if (opline->opcode == ZEND_IS_EQUAL ||
769 opline->opcode == ZEND_IS_NOT_EQUAL ||
770
771 (opline->opcode == ZEND_CASE && (ZEND_OP1_TYPE(opline) & (IS_CONST|IS_CV)))) {
772 if (ZEND_OP1_TYPE(opline) == IS_CONST &&
773 (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_FALSE ||
774 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_TRUE)) {
775
776
777
778
779
780
781
782 opline->opcode =
783 ((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP1_LITERAL(opline))) == IS_TRUE)) ?
784 ZEND_BOOL : ZEND_BOOL_NOT;
785 COPY_NODE(opline->op1, opline->op2);
786 SET_UNUSED(opline->op2);
787 } else if (ZEND_OP2_TYPE(opline) == IS_CONST &&
788 (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_FALSE ||
789 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_TRUE)) {
790
791
792
793
794
795
796
797 opline->opcode =
798 ((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP2_LITERAL(opline))) == IS_TRUE)) ?
799 ZEND_BOOL : ZEND_BOOL_NOT;
800 SET_UNUSED(opline->op2);
801 }
802 }
803
804 if ((opline->opcode == ZEND_BOOL ||
805 opline->opcode == ZEND_BOOL_NOT ||
806 opline->opcode == ZEND_JMPZ ||
807 opline->opcode == ZEND_JMPNZ ||
808 opline->opcode == ZEND_JMPZNZ) &&
809 ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
810 VAR_SOURCE(opline->op1) != NULL &&
811 !zend_bitset_in(used_ext, VAR_NUM(ZEND_OP1(opline).var)) &&
812 VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL_NOT) {
813
814 zend_op *src = VAR_SOURCE(opline->op1);
815
816 COPY_NODE(opline->op1, src->op1);
817
818 switch (opline->opcode) {
819 case ZEND_BOOL:
820
821 opline->opcode = ZEND_BOOL_NOT;
822 break;
823 case ZEND_BOOL_NOT:
824
825 opline->opcode = ZEND_BOOL;
826 break;
827 case ZEND_JMPZ:
828
829 opline->opcode = ZEND_JMPNZ;
830 break;
831 case ZEND_JMPNZ:
832
833 opline->opcode = ZEND_JMPZ;
834 break;
835 case ZEND_JMPZNZ:
836 {
837
838 int op_t;
839 zend_code_block *op_b;
840
841 op_t = opline->extended_value;
842 opline->extended_value = ZEND_OP2(opline).opline_num;
843 ZEND_OP2(opline).opline_num = op_t;
844
845 op_b = block->ext_to;
846 block->ext_to = block->op2_to;
847 block->op2_to = op_b;
848 }
849 break;
850 }
851
852 VAR_UNSET(opline->op1);
853 MAKE_NOP(src);
854 continue;
855 } else
856 #if 0
857
858 if(0 && (opline->opcode == ZEND_JMPZ_EX ||
859 opline->opcode == ZEND_JMPNZ_EX) &&
860 ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
861 VAR_SOURCE(opline->op1) != NULL &&
862 VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL_NOT &&
863 ZEND_OP1(opline).var == ZEND_RESULT(opline).var
864 ) {
865 zend_op *src = VAR_SOURCE(opline->op1);
866 if(opline->opcode == ZEND_JMPZ_EX) {
867 opline->opcode = ZEND_JMPNZ;
868 } else {
869 opline->opcode = ZEND_JMPZ;
870 }
871 COPY_NODE(opline->op1, src->op1);
872 SET_UNUSED(opline->result);
873 continue;
874 } else
875 #endif
876
877 if ((opline->opcode == ZEND_BOOL ||
878 opline->opcode == ZEND_BOOL_NOT ||
879 opline->opcode == ZEND_JMPZ ||
880 opline->opcode == ZEND_JMPZ_EX ||
881 opline->opcode == ZEND_JMPNZ_EX ||
882 opline->opcode == ZEND_JMPNZ ||
883 opline->opcode == ZEND_JMPZNZ) &&
884 (ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
885 VAR_SOURCE(opline->op1) != NULL &&
886 (!zend_bitset_in(used_ext, VAR_NUM(ZEND_OP1(opline).var)) ||
887 ((ZEND_RESULT_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
888 ZEND_RESULT(opline).var == ZEND_OP1(opline).var)) &&
889 (VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL ||
890 VAR_SOURCE(opline->op1)->opcode == ZEND_QM_ASSIGN)) {
891 zend_op *src = VAR_SOURCE(opline->op1);
892 COPY_NODE(opline->op1, src->op1);
893
894 VAR_UNSET(opline->op1);
895 MAKE_NOP(src);
896 continue;
897 } else if (last_op && opline->opcode == ZEND_ECHO &&
898 last_op->opcode == ZEND_ECHO &&
899 ZEND_OP1_TYPE(opline) == IS_CONST &&
900 Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_DOUBLE &&
901 ZEND_OP1_TYPE(last_op) == IS_CONST &&
902 Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_DOUBLE) {
903
904
905
906
907 int l, old_len;
908
909 if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
910 convert_to_string_safe(&ZEND_OP1_LITERAL(opline));
911 }
912 if (Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_STRING) {
913 convert_to_string_safe(&ZEND_OP1_LITERAL(last_op));
914 }
915 old_len = Z_STRLEN(ZEND_OP1_LITERAL(last_op));
916 l = old_len + Z_STRLEN(ZEND_OP1_LITERAL(opline));
917 if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(last_op))) {
918 zend_string *tmp = zend_string_alloc(l, 0);
919 memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP1_LITERAL(last_op)), old_len);
920 Z_STR(ZEND_OP1_LITERAL(last_op)) = tmp;
921 } else {
922 Z_STR(ZEND_OP1_LITERAL(last_op)) = zend_string_extend(Z_STR(ZEND_OP1_LITERAL(last_op)), l, 0);
923 }
924 Z_TYPE_INFO(ZEND_OP1_LITERAL(last_op)) = IS_STRING_EX;
925 memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op)) + old_len, Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)));
926 Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0';
927 zval_dtor(&ZEND_OP1_LITERAL(opline));
928 ZVAL_STR(&ZEND_OP1_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op))));
929 ZVAL_NULL(&ZEND_OP1_LITERAL(last_op));
930 MAKE_NOP(last_op);
931 } else if ((opline->opcode == ZEND_CONCAT) &&
932 ZEND_OP2_TYPE(opline) == IS_CONST &&
933 ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
934 VAR_SOURCE(opline->op1) &&
935 (VAR_SOURCE(opline->op1)->opcode == ZEND_CONCAT ||
936 VAR_SOURCE(opline->op1)->opcode == ZEND_FAST_CONCAT) &&
937 ZEND_OP2_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST &&
938 ZEND_RESULT(VAR_SOURCE(opline->op1)).var == ZEND_OP1(opline).var) {
939
940 zend_op *src = VAR_SOURCE(opline->op1);
941 int l, old_len;
942
943 if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
944 convert_to_string_safe(&ZEND_OP2_LITERAL(opline));
945 }
946 if (Z_TYPE(ZEND_OP2_LITERAL(src)) != IS_STRING) {
947 convert_to_string_safe(&ZEND_OP2_LITERAL(src));
948 }
949
950 VAR_UNSET(opline->op1);
951 COPY_NODE(opline->op1, src->op1);
952 old_len = Z_STRLEN(ZEND_OP2_LITERAL(src));
953 l = old_len + Z_STRLEN(ZEND_OP2_LITERAL(opline));
954 if (!Z_REFCOUNTED(ZEND_OP2_LITERAL(src))) {
955 zend_string *tmp = zend_string_alloc(l, 0);
956 memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP2_LITERAL(src)), old_len);
957 Z_STR(ZEND_OP2_LITERAL(last_op)) = tmp;
958 } else {
959 Z_STR(ZEND_OP2_LITERAL(src)) = zend_string_extend(Z_STR(ZEND_OP2_LITERAL(src)), l, 0);
960 }
961 Z_TYPE_INFO(ZEND_OP2_LITERAL(last_op)) = IS_STRING_EX;
962 memcpy(Z_STRVAL(ZEND_OP2_LITERAL(src)) + old_len, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
963 Z_STRVAL(ZEND_OP2_LITERAL(src))[l] = '\0';
964 zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline)));
965 ZVAL_STR(&ZEND_OP2_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP2_LITERAL(src))));
966 ZVAL_NULL(&ZEND_OP2_LITERAL(src));
967 MAKE_NOP(src);
968 } else if ((opline->opcode == ZEND_ADD ||
969 opline->opcode == ZEND_SUB ||
970 opline->opcode == ZEND_MUL ||
971 opline->opcode == ZEND_DIV ||
972 opline->opcode == ZEND_MOD ||
973 opline->opcode == ZEND_SL ||
974 opline->opcode == ZEND_SR ||
975 opline->opcode == ZEND_CONCAT ||
976 opline->opcode == ZEND_FAST_CONCAT ||
977 opline->opcode == ZEND_IS_EQUAL ||
978 opline->opcode == ZEND_IS_NOT_EQUAL ||
979 opline->opcode == ZEND_IS_SMALLER ||
980 opline->opcode == ZEND_IS_SMALLER_OR_EQUAL ||
981 opline->opcode == ZEND_IS_IDENTICAL ||
982 opline->opcode == ZEND_IS_NOT_IDENTICAL ||
983 opline->opcode == ZEND_BOOL_XOR ||
984 opline->opcode == ZEND_BW_OR ||
985 opline->opcode == ZEND_BW_AND ||
986 opline->opcode == ZEND_BW_XOR) &&
987 ZEND_OP1_TYPE(opline)==IS_CONST &&
988 ZEND_OP2_TYPE(opline)==IS_CONST) {
989
990 binary_op_type binary_op = get_binary_op(opline->opcode);
991 zval result;
992 int er;
993
994 if ((opline->opcode == ZEND_DIV || opline->opcode == ZEND_MOD) &&
995 zval_get_long(&ZEND_OP2_LITERAL(opline)) == 0) {
996 if (RESULT_USED(opline)) {
997 SET_VAR_SOURCE(opline);
998 }
999 opline++;
1000 continue;
1001 } else if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR) &&
1002 zval_get_long(&ZEND_OP2_LITERAL(opline)) < 0) {
1003 if (RESULT_USED(opline)) {
1004 SET_VAR_SOURCE(opline);
1005 }
1006 opline++;
1007 continue;
1008 }
1009 er = EG(error_reporting);
1010 EG(error_reporting) = 0;
1011 if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
1012 literal_dtor(&ZEND_OP1_LITERAL(opline));
1013 literal_dtor(&ZEND_OP2_LITERAL(opline));
1014 opline->opcode = ZEND_QM_ASSIGN;
1015 SET_UNUSED(opline->op2);
1016 zend_optimizer_update_op1_const(op_array, opline, &result);
1017 }
1018 EG(error_reporting) = er;
1019 } else if ((opline->opcode == ZEND_BOOL ||
1020 opline->opcode == ZEND_BOOL_NOT ||
1021 opline->opcode == ZEND_BW_NOT) && ZEND_OP1_TYPE(opline) == IS_CONST) {
1022
1023 unary_op_type unary_op = get_unary_op(opline->opcode);
1024 zval result;
1025
1026 if (unary_op) {
1027 unary_op(&result, &ZEND_OP1_LITERAL(opline));
1028 literal_dtor(&ZEND_OP1_LITERAL(opline));
1029 } else {
1030
1031 result = ZEND_OP1_LITERAL(opline);
1032 convert_to_boolean(&result);
1033 ZVAL_NULL(&ZEND_OP1_LITERAL(opline));
1034 }
1035 opline->opcode = ZEND_QM_ASSIGN;
1036 zend_optimizer_update_op1_const(op_array, opline, &result);
1037 } else if ((opline->opcode == ZEND_RETURN || opline->opcode == ZEND_EXIT) &&
1038 (ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
1039 VAR_SOURCE(opline->op1) &&
1040 VAR_SOURCE(opline->op1)->opcode == ZEND_QM_ASSIGN) {
1041
1042 zend_op *src = VAR_SOURCE(opline->op1);
1043 VAR_UNSET(opline->op1);
1044 COPY_NODE(opline->op1, src->op1);
1045 MAKE_NOP(src);
1046 } else if (opline->opcode == ZEND_CONCAT || opline->opcode == ZEND_FAST_CONCAT) {
1047 if ((ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
1048 VAR_SOURCE(opline->op1) &&
1049 VAR_SOURCE(opline->op1)->opcode == ZEND_CAST &&
1050 VAR_SOURCE(opline->op1)->extended_value == IS_STRING) {
1051
1052 zend_op *src = VAR_SOURCE(opline->op1);
1053 VAR_UNSET(opline->op1);
1054 COPY_NODE(opline->op1, src->op1);
1055 MAKE_NOP(src);
1056 }
1057 if ((ZEND_OP2_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
1058 VAR_SOURCE(opline->op2) &&
1059 VAR_SOURCE(opline->op2)->opcode == ZEND_CAST &&
1060 VAR_SOURCE(opline->op2)->extended_value == IS_STRING) {
1061
1062 zend_op *src = VAR_SOURCE(opline->op2);
1063 VAR_UNSET(opline->op2);
1064 COPY_NODE(opline->op2, src->op1);
1065 MAKE_NOP(src);
1066 }
1067 if (ZEND_OP1_TYPE(opline) == IS_CONST &&
1068 Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
1069 Z_STRLEN(ZEND_OP1_LITERAL(opline)) == 0) {
1070
1071 literal_dtor(&ZEND_OP1_LITERAL(opline));
1072 opline->opcode = ZEND_CAST;
1073 opline->extended_value = IS_STRING;
1074 COPY_NODE(opline->op1, opline->op2);
1075 opline->op2_type = IS_UNUSED;
1076 opline->op2.var = 0;
1077 } else if (ZEND_OP2_TYPE(opline) == IS_CONST &&
1078 Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
1079 Z_STRLEN(ZEND_OP2_LITERAL(opline)) == 0) {
1080
1081 literal_dtor(&ZEND_OP2_LITERAL(opline));
1082 opline->opcode = ZEND_CAST;
1083 opline->extended_value = IS_STRING;
1084 opline->op2_type = IS_UNUSED;
1085 opline->op2.var = 0;
1086 } else if (opline->opcode == ZEND_CONCAT &&
1087 (opline->op1_type == IS_CONST ||
1088 (opline->op1_type == IS_TMP_VAR &&
1089 VAR_SOURCE(opline->op1) &&
1090 (VAR_SOURCE(opline->op1)->opcode == ZEND_FAST_CONCAT ||
1091 VAR_SOURCE(opline->op1)->opcode == ZEND_ROPE_END ||
1092 VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CONSTANT))) &&
1093 (opline->op2_type == IS_CONST ||
1094 (opline->op2_type == IS_TMP_VAR &&
1095 VAR_SOURCE(opline->op2) &&
1096 (VAR_SOURCE(opline->op2)->opcode == ZEND_FAST_CONCAT ||
1097 VAR_SOURCE(opline->op2)->opcode == ZEND_ROPE_END ||
1098 VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CONSTANT)))) {
1099 opline->opcode = ZEND_FAST_CONCAT;
1100 }
1101 } else if (opline->opcode == ZEND_QM_ASSIGN &&
1102 ZEND_OP1_TYPE(opline) == ZEND_RESULT_TYPE(opline) &&
1103 ZEND_OP1(opline).var == ZEND_RESULT(opline).var) {
1104
1105 MAKE_NOP(opline);
1106 } else if (opline->opcode == ZEND_BOOL &&
1107 ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
1108 VAR_SOURCE(opline->op1) &&
1109 (VAR_SOURCE(opline->op1)->opcode == ZEND_IS_EQUAL ||
1110 VAR_SOURCE(opline->op1)->opcode == ZEND_IS_NOT_EQUAL ||
1111 VAR_SOURCE(opline->op1)->opcode == ZEND_IS_SMALLER ||
1112 VAR_SOURCE(opline->op1)->opcode == ZEND_IS_SMALLER_OR_EQUAL ||
1113 VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL ||
1114 VAR_SOURCE(opline->op1)->opcode == ZEND_IS_IDENTICAL ||
1115 VAR_SOURCE(opline->op1)->opcode == ZEND_IS_NOT_IDENTICAL ||
1116 VAR_SOURCE(opline->op1)->opcode == ZEND_ISSET_ISEMPTY_VAR ||
1117 VAR_SOURCE(opline->op1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ) &&
1118 !zend_bitset_in(used_ext, VAR_NUM(ZEND_OP1(opline).var))) {
1119
1120 zend_op *src = VAR_SOURCE(opline->op1);
1121 COPY_NODE(src->result, opline->result);
1122 SET_VAR_SOURCE(src);
1123 MAKE_NOP(opline);
1124 }
1125
1126 if (RESULT_USED(opline)) {
1127 SET_VAR_SOURCE(opline);
1128 }
1129 if (opline->opcode != ZEND_NOP) {
1130 last_op = opline;
1131 }
1132 opline++;
1133 }
1134
1135 strip_nop(block, ctx);
1136 }
1137
1138
1139 static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array)
1140 {
1141 zend_code_block *blocks = cfg->blocks;
1142 zend_op *new_opcodes = emalloc(op_array->last * sizeof(zend_op));
1143 zend_op *opline = new_opcodes;
1144 zend_code_block *cur_block = blocks;
1145
1146
1147 while (cur_block) {
1148 if (cur_block->access) {
1149 memcpy(opline, cur_block->start_opline, cur_block->len * sizeof(zend_op));
1150 cur_block->start_opline = opline;
1151 opline += cur_block->len;
1152 if ((opline - 1)->opcode == ZEND_JMP) {
1153 zend_code_block *next;
1154 next = cur_block->next;
1155 while (next && !next->access) {
1156 next = next->next;
1157 }
1158 if (next && next == cur_block->op1_to) {
1159
1160 cur_block->follow_to = cur_block->op1_to;
1161 cur_block->op1_to = NULL;
1162 MAKE_NOP((opline - 1));
1163 opline--;
1164 cur_block->len--;
1165 }
1166 }
1167 } else {
1168
1169 zend_op *_opl;
1170 zend_op *end = cur_block->start_opline + cur_block->len;
1171 for (_opl = cur_block->start_opline; _opl && _opl < end; _opl++) {
1172 if (ZEND_OP1_TYPE(_opl) == IS_CONST) {
1173 literal_dtor(&ZEND_OP1_LITERAL(_opl));
1174 }
1175 if (ZEND_OP2_TYPE(_opl) == IS_CONST) {
1176 literal_dtor(&ZEND_OP2_LITERAL(_opl));
1177 }
1178 }
1179 }
1180 cur_block = cur_block->next;
1181 }
1182
1183 op_array->last = opline-new_opcodes;
1184
1185
1186 if (op_array->last_try_catch) {
1187 int i, j;
1188 for (i = 0, j = 0; i< op_array->last_try_catch; i++) {
1189 if (cfg->try[i]->access) {
1190 op_array->try_catch_array[j].try_op = cfg->try[i]->start_opline - new_opcodes;
1191 op_array->try_catch_array[j].catch_op = cfg->catch[i]->start_opline - new_opcodes;
1192 j++;
1193 }
1194 }
1195 op_array->last_try_catch = j;
1196 }
1197
1198
1199 if (op_array->last_brk_cont) {
1200 int i;
1201 for (i = 0; i< op_array->last_brk_cont; i++) {
1202 op_array->brk_cont_array[i].start = cfg->loop_start[i]->start_opline - new_opcodes;
1203 op_array->brk_cont_array[i].cont = cfg->loop_cont[i]->start_opline - new_opcodes;
1204 op_array->brk_cont_array[i].brk = cfg->loop_brk[i]->start_opline - new_opcodes;
1205 }
1206 }
1207
1208
1209 for (cur_block = blocks; cur_block; cur_block = cur_block->next) {
1210 if (!cur_block->access) {
1211 continue;
1212 }
1213 opline = cur_block->start_opline + cur_block->len - 1;
1214 if (opline->opcode == ZEND_OP_DATA) {
1215 opline--;
1216 }
1217 if (cur_block->op1_to) {
1218 ZEND_OP1(opline).opline_num = cur_block->op1_to->start_opline - new_opcodes;
1219 }
1220 if (cur_block->op2_to) {
1221 ZEND_OP2(opline).opline_num = cur_block->op2_to->start_opline - new_opcodes;
1222 }
1223 if (cur_block->ext_to) {
1224 opline->extended_value = cur_block->ext_to->start_opline - new_opcodes;
1225 }
1226 print_block(cur_block, new_opcodes, "Out ");
1227 }
1228 efree(op_array->opcodes);
1229 op_array->opcodes = erealloc(new_opcodes, op_array->last * sizeof(zend_op));
1230
1231
1232 if (op_array->early_binding != (uint32_t)-1) {
1233 uint32_t *opline_num = &op_array->early_binding;
1234 zend_op *end;
1235
1236 opline = op_array->opcodes;
1237 end = opline + op_array->last;
1238 while (opline < end) {
1239 if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
1240 *opline_num = opline - op_array->opcodes;
1241 opline_num = &ZEND_RESULT(opline).opline_num;
1242 }
1243 ++opline;
1244 }
1245 *opline_num = -1;
1246 }
1247 }
1248
1249 static void zend_jmp_optimization(zend_code_block *block, zend_op_array *op_array, zend_code_block *blocks, zend_cfg *cfg, zend_optimizer_ctx *ctx)
1250 {
1251
1252 zend_op *last_op = (block->start_opline + block->len - 1);
1253
1254 if (!block->len) {
1255 return;
1256 }
1257 switch (last_op->opcode) {
1258 case ZEND_JMP:
1259 {
1260 zend_op *target = block->op1_to->start_opline;
1261 zend_code_block *next = block->next;
1262
1263 while (next && !next->access) {
1264
1265 next = next->next;
1266 }
1267
1268
1269 if (block->op1_to == next) {
1270 block->follow_to = block->op1_to;
1271 block->op1_to = NULL;
1272 MAKE_NOP(last_op);
1273 block->len--;
1274 if (block->len == 0) {
1275
1276 delete_code_block(block, ctx);
1277 }
1278 break;
1279 }
1280
1281 if (((target->opcode == ZEND_JMP &&
1282 block->op1_to != block->op1_to->op1_to) ||
1283 target->opcode == ZEND_JMPZNZ) &&
1284 !block->op1_to->protected) {
1285
1286
1287 *last_op = *target;
1288 if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
1289 zval zv = ZEND_OP1_LITERAL(last_op);
1290 zval_copy_ctor(&zv);
1291 last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
1292 }
1293 del_source(block, block->op1_to);
1294 if (block->op1_to->op2_to) {
1295 block->op2_to = block->op1_to->op2_to;
1296 ADD_SOURCE(block, block->op2_to);
1297 }
1298 if (block->op1_to->ext_to) {
1299 block->ext_to = block->op1_to->ext_to;
1300 ADD_SOURCE(block, block->ext_to);
1301 }
1302 if (block->op1_to->op1_to) {
1303 block->op1_to = block->op1_to->op1_to;
1304 ADD_SOURCE(block, block->op1_to);
1305 } else {
1306 block->op1_to = NULL;
1307 }
1308 } else if (target->opcode == ZEND_RETURN ||
1309 target->opcode == ZEND_RETURN_BY_REF ||
1310 target->opcode == ZEND_FAST_RET ||
1311 target->opcode == ZEND_EXIT) {
1312
1313 *last_op = *target;
1314 if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
1315 zval zv = ZEND_OP1_LITERAL(last_op);
1316 zval_copy_ctor(&zv);
1317 last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
1318 }
1319 del_source(block, block->op1_to);
1320 block->op1_to = NULL;
1321 #if 0
1322
1323 } else if (0&& block->op1_to != block &&
1324 block->op1_to != blocks &&
1325 op_array->last_try_catch == 0 &&
1326 target->opcode != ZEND_FREE) {
1327
1328
1329
1330
1331 zend_bool can_reorder = 0;
1332 zend_block_source *cs = block->op1_to->sources;
1333
1334
1335 while(cs) {
1336 if (cs->from->follow_to == block->op1_to) {
1337 can_reorder = 0;
1338 break;
1339 }
1340 cs = cs->next;
1341 }
1342 if (can_reorder) {
1343 next = block->op1_to;
1344
1345 while (next->follow_to != NULL) {
1346 if (next->follow_to == block) {
1347 can_reorder = 0;
1348 break;
1349 }
1350 next = next->follow_to;
1351 }
1352 if (can_reorder) {
1353 zend_code_block *prev = blocks;
1354
1355 while (prev->next != block->op1_to) {
1356 prev = prev->next;
1357 }
1358 prev->next = next->next;
1359 next->next = block->next;
1360 block->next = block->op1_to;
1361
1362 block->follow_to = block->op1_to;
1363 block->op1_to = NULL;
1364 MAKE_NOP(last_op);
1365 block->len--;
1366 if(block->len == 0) {
1367
1368 delete_code_block(block, ctx);
1369 }
1370 break;
1371 }
1372 }
1373 #endif
1374 }
1375 }
1376 break;
1377
1378 case ZEND_JMPZ:
1379 case ZEND_JMPNZ:
1380
1381 if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
1382 int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
1383
1384 if (last_op->opcode == ZEND_JMPZ) {
1385 should_jmp = !should_jmp;
1386 }
1387 literal_dtor(&ZEND_OP1_LITERAL(last_op));
1388 ZEND_OP1_TYPE(last_op) = IS_UNUSED;
1389 if (should_jmp) {
1390
1391 last_op->opcode = ZEND_JMP;
1392 COPY_NODE(last_op->op1, last_op->op2);
1393 block->op1_to = block->op2_to;
1394 del_source(block, block->follow_to);
1395 block->op2_to = NULL;
1396 block->follow_to = NULL;
1397 } else {
1398
1399 MAKE_NOP(last_op);
1400 del_source(block, block->op2_to);
1401 block->op2_to = NULL;
1402 }
1403 break;
1404 }
1405
1406 if (block->op2_to == block->follow_to) {
1407
1408
1409 if (last_op->op1_type == IS_VAR) {
1410 zend_op **Tsource = cfg->Tsource;
1411 zend_op *src = VAR_SOURCE(last_op->op1);
1412
1413 if (src &&
1414 src->opcode != ZEND_FETCH_R &&
1415 src->opcode != ZEND_FETCH_DIM_R &&
1416 src->opcode != ZEND_FETCH_OBJ_R) {
1417 ZEND_RESULT_TYPE(src) |= EXT_TYPE_UNUSED;
1418 MAKE_NOP(last_op);
1419 block->op2_to = NULL;
1420 break;
1421 }
1422 }
1423 if (last_op->op1_type & (IS_VAR|IS_TMP_VAR)) {
1424 last_op->opcode = ZEND_FREE;
1425 last_op->op2.num = 0;
1426 block->op2_to = NULL;
1427 } else {
1428 MAKE_NOP(last_op);
1429 block->op2_to = NULL;
1430 }
1431 break;
1432 }
1433
1434 if (block->op2_to) {
1435 zend_uchar same_type = ZEND_OP1_TYPE(last_op);
1436 uint32_t same_var = VAR_NUM_EX(last_op->op1);
1437 zend_op *target;
1438 zend_op *target_end;
1439 zend_code_block *target_block = block->op2_to;;
1440
1441 next_target:
1442 target = target_block->start_opline;
1443 target_end = target_block->start_opline + target_block->len;
1444 while (target < target_end && target->opcode == ZEND_NOP) {
1445 target++;
1446 }
1447
1448
1449 if (target == target_end) {
1450 target_block = target_block->follow_to;
1451 goto next_target;
1452 } else if (target->opcode == INV_COND(last_op->opcode) &&
1453
1454 (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
1455 same_type == ZEND_OP1_TYPE(target) &&
1456 same_var == VAR_NUM_EX(target->op1) &&
1457 target_block->follow_to &&
1458 !target_block->protected
1459 ) {
1460 del_source(block, block->op2_to);
1461 block->op2_to = target_block->follow_to;
1462 ADD_SOURCE(block, block->op2_to);
1463 } else if (target->opcode == INV_COND_EX(last_op->opcode) &&
1464 (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
1465 same_type == ZEND_OP1_TYPE(target) &&
1466 same_var == VAR_NUM_EX(target->op1) &&
1467 target_block->follow_to &&
1468 !target_block->protected) {
1469
1470 last_op->opcode += 3;
1471 last_op->result = target->result;
1472 del_source(block, block->op2_to);
1473 block->op2_to = target_block->follow_to;
1474 ADD_SOURCE(block, block->op2_to);
1475 } else if (target_block->op2_to &&
1476 target->opcode == last_op->opcode &&
1477 (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
1478 same_type == ZEND_OP1_TYPE(target) &&
1479 same_var == VAR_NUM_EX(target->op1) &&
1480 !target_block->protected) {
1481
1482 del_source(block, block->op2_to);
1483 block->op2_to = target_block->op2_to;
1484 ADD_SOURCE(block, block->op2_to);
1485 } else if (target_block->op1_to &&
1486 target->opcode == ZEND_JMP &&
1487 !target_block->protected) {
1488
1489 del_source(block, block->op2_to);
1490 block->op2_to = target_block->op1_to;
1491 ADD_SOURCE(block, block->op2_to);
1492 } else if (target_block->op2_to &&
1493 target_block->ext_to &&
1494 target->opcode == ZEND_JMPZNZ &&
1495 (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
1496 same_type == ZEND_OP1_TYPE(target) &&
1497 same_var == VAR_NUM_EX(target->op1) &&
1498 !target_block->protected) {
1499
1500 del_source(block, block->op2_to);
1501 if (last_op->opcode == ZEND_JMPZ) {
1502 block->op2_to = target_block->op2_to;
1503 } else {
1504 block->op2_to = target_block->ext_to;
1505 }
1506 ADD_SOURCE(block, block->op2_to);
1507 }
1508 }
1509
1510 if (block->follow_to &&
1511 (last_op->opcode == ZEND_JMPZ || last_op->opcode == ZEND_JMPNZ)) {
1512 zend_op *target;
1513 zend_op *target_end;
1514
1515 while (1) {
1516 target = block->follow_to->start_opline;
1517 target_end = block->follow_to->start_opline + block->follow_to->len;
1518 while (target < target_end && target->opcode == ZEND_NOP) {
1519 target++;
1520 }
1521
1522
1523 if (target == target_end && ! block->follow_to->protected) {
1524 del_source(block, block->follow_to);
1525 block->follow_to = block->follow_to->follow_to;
1526 ADD_SOURCE(block, block->follow_to);
1527 } else {
1528 break;
1529 }
1530 }
1531
1532 if (target->opcode == ZEND_JMP &&
1533 block->follow_to->op1_to &&
1534 !block->follow_to->protected) {
1535 del_source(block, block->follow_to);
1536 if (last_op->opcode == ZEND_JMPZ) {
1537 block->ext_to = block->follow_to->op1_to;
1538 ADD_SOURCE(block, block->ext_to);
1539 } else {
1540 block->ext_to = block->op2_to;
1541 block->op2_to = block->follow_to->op1_to;
1542 ADD_SOURCE(block, block->op2_to);
1543 }
1544 block->follow_to = NULL;
1545 last_op->opcode = ZEND_JMPZNZ;
1546 }
1547 }
1548 break;
1549
1550 case ZEND_JMPNZ_EX:
1551 case ZEND_JMPZ_EX:
1552
1553 if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
1554 int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
1555
1556 if (last_op->opcode == ZEND_JMPZ_EX) {
1557 should_jmp = !should_jmp;
1558 }
1559 if (!should_jmp) {
1560
1561
1562
1563 last_op->opcode = ZEND_QM_ASSIGN;
1564 SET_UNUSED(last_op->op2);
1565 del_source(block, block->op2_to);
1566 block->op2_to = NULL;
1567 }
1568 break;
1569 }
1570
1571 if (block->op2_to) {
1572 zend_op *target, *target_end;
1573 char *same_t=NULL;
1574 zend_code_block *target_block;
1575 int var_num = op_array->last_var + op_array->T;
1576
1577 if (var_num <= 0) {
1578 return;
1579 }
1580 same_t = cfg->same_t;
1581 memset(same_t, 0, var_num);
1582 same_t[VAR_NUM_EX(last_op->op1)] |= ZEND_OP1_TYPE(last_op);
1583 same_t[VAR_NUM_EX(last_op->result)] |= ZEND_RESULT_TYPE(last_op);
1584 target_block = block->op2_to;
1585 next_target_ex:
1586 target = target_block->start_opline;
1587 target_end = target_block->start_opline + target_block->len;
1588 while (target < target_end && target->opcode == ZEND_NOP) {
1589 target++;
1590 }
1591
1592 if (target == target_end) {
1593 target_block = target_block->follow_to;
1594 goto next_target_ex;
1595 } else if (target_block->op2_to &&
1596 target->opcode == last_op->opcode-3 &&
1597 (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
1598 (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
1599 !target_block->protected) {
1600
1601 del_source(block, block->op2_to);
1602 block->op2_to = target_block->op2_to;
1603 ADD_SOURCE(block, block->op2_to);
1604 } else if (target_block->op2_to &&
1605 target->opcode == INV_EX_COND(last_op->opcode) &&
1606 (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
1607 (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
1608 !target_block->protected) {
1609
1610 del_source(block, block->op2_to);
1611 block->op2_to = target_block->follow_to;
1612 ADD_SOURCE(block, block->op2_to);
1613 } else if (target_block->op2_to &&
1614 target->opcode == INV_EX_COND_EX(last_op->opcode) &&
1615 (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
1616 (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
1617 (same_t[VAR_NUM_EX(target->result)] & ZEND_RESULT_TYPE(target)) != 0 &&
1618 !target_block->protected) {
1619
1620 del_source(block, block->op2_to);
1621 block->op2_to = target_block->follow_to;
1622 ADD_SOURCE(block, block->op2_to);
1623 } else if (target_block->op2_to &&
1624 target->opcode == last_op->opcode &&
1625 (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
1626 (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
1627 (same_t[VAR_NUM_EX(target->result)] & ZEND_RESULT_TYPE(target)) != 0 &&
1628 !target_block->protected) {
1629
1630 del_source(block, block->op2_to);
1631 block->op2_to = target_block->op2_to;
1632 ADD_SOURCE(block, block->op2_to);
1633 } else if (target_block->op1_to &&
1634 target->opcode == ZEND_JMP &&
1635 !target_block->protected) {
1636
1637 del_source(block, block->op2_to);
1638 block->op2_to = target_block->op1_to;
1639 ADD_SOURCE(block, block->op2_to);
1640 } else if (target_block->op2_to &&
1641 target_block->ext_to &&
1642 target->opcode == ZEND_JMPZNZ &&
1643 (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
1644 (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
1645 !target_block->protected) {
1646
1647 del_source(block, block->op2_to);
1648 if (last_op->opcode == ZEND_JMPZ_EX) {
1649 block->op2_to = target_block->op2_to;
1650 } else {
1651 block->op2_to = target_block->ext_to;
1652 }
1653 ADD_SOURCE(block, block->op2_to);
1654 }
1655 }
1656 break;
1657
1658 case ZEND_JMPZNZ: {
1659 zend_code_block *next = block->next;
1660
1661 while (next && !next->access) {
1662
1663 next = next->next;
1664 }
1665
1666 if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
1667 if (!zend_is_true(&ZEND_OP1_LITERAL(last_op))) {
1668
1669 zend_code_block *todel;
1670
1671 literal_dtor(&ZEND_OP1_LITERAL(last_op));
1672 last_op->opcode = ZEND_JMP;
1673 SET_UNUSED(last_op->op1);
1674 SET_UNUSED(last_op->op2);
1675 block->op1_to = block->op2_to;
1676 todel = block->ext_to;
1677 block->op2_to = NULL;
1678 block->ext_to = NULL;
1679 del_source(block, todel);
1680 } else {
1681
1682 zend_code_block *todel;
1683
1684 literal_dtor(&ZEND_OP1_LITERAL(last_op));
1685 last_op->opcode = ZEND_JMP;
1686 SET_UNUSED(last_op->op1);
1687 SET_UNUSED(last_op->op2);
1688 block->op1_to = block->ext_to;
1689 todel = block->op2_to;
1690 block->op2_to = NULL;
1691 block->ext_to = NULL;
1692 del_source(block, todel);
1693 }
1694 } else if (block->op2_to == block->ext_to) {
1695
1696 if (!(last_op->op1_type & (IS_VAR|IS_TMP_VAR))) {
1697
1698 last_op->opcode = ZEND_JMP;
1699 SET_UNUSED(last_op->op1);
1700 SET_UNUSED(last_op->op2);
1701 block->op1_to = block->op2_to;
1702 block->op2_to = NULL;
1703 block->ext_to = NULL;
1704 }
1705 } else if (block->op2_to == next) {
1706
1707
1708 last_op->opcode = ZEND_JMPNZ;
1709 block->op2_to = block->ext_to;
1710 block->follow_to = next;
1711 block->ext_to = NULL;
1712
1713 } else if (block->ext_to == next) {
1714
1715
1716 last_op->opcode = ZEND_JMPZ;
1717 block->follow_to = next;
1718 block->ext_to = NULL;
1719
1720 }
1721
1722 if (last_op->opcode == ZEND_JMPZNZ && block->op2_to) {
1723 zend_uchar same_type = ZEND_OP1_TYPE(last_op);
1724 zend_uchar same_var = VAR_NUM_EX(last_op->op1);
1725 zend_op *target;
1726 zend_op *target_end;
1727 zend_code_block *target_block = block->op2_to;
1728
1729 next_target_znz:
1730 target = target_block->start_opline;
1731 target_end = target_block->start_opline + target_block->len;
1732 while (target < target_end && target->opcode == ZEND_NOP) {
1733 target++;
1734 }
1735
1736 if (target == target_end) {
1737 target_block = target_block->follow_to;
1738 goto next_target_znz;
1739 } else if (target_block->op2_to &&
1740 (target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
1741 (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
1742 same_type == ZEND_OP1_TYPE(target) &&
1743 same_var == VAR_NUM_EX(target->op1) &&
1744 !target_block->protected) {
1745
1746 del_source(block, block->op2_to);
1747 block->op2_to = target_block->op2_to;
1748 ADD_SOURCE(block, block->op2_to);
1749 } else if (target->opcode == ZEND_JMPNZ &&
1750 (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
1751 same_type == ZEND_OP1_TYPE(target) &&
1752 same_var == VAR_NUM_EX(target->op1) &&
1753 target_block->follow_to &&
1754 !target_block->protected) {
1755
1756 del_source(block, block->op2_to);
1757 block->op2_to = target_block->follow_to;
1758 ADD_SOURCE(block, block->op2_to);
1759 } else if (target_block->op1_to &&
1760 target->opcode == ZEND_JMP &&
1761 !target_block->protected) {
1762
1763 del_source(block, block->op2_to);
1764 block->op2_to = target_block->op1_to;
1765 ADD_SOURCE(block, block->op2_to);
1766 }
1767 }
1768 break;
1769 }
1770 }
1771 }
1772
1773
1774
1775 #define T_USAGE(op) do { \
1776 if ((op ## _type & (IS_VAR | IS_TMP_VAR)) && \
1777 !zend_bitset_in(defined_here, VAR_NUM(op.var)) && !zend_bitset_in(used_ext, VAR_NUM(op.var))) { \
1778 zend_bitset_incl(used_ext, VAR_NUM(op.var)); \
1779 } \
1780 } while (0)
1781
1782 #define NEVER_USED(op) ((op ## _type & (IS_VAR | IS_TMP_VAR)) && !zend_bitset_in(usage, VAR_NUM(op.var)))
1783 #define RES_NEVER_USED(opline) (opline->result_type == IS_UNUSED || NEVER_USED(opline->result))
1784
1785
1786
1787 static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, zend_bitset used_ext, zend_optimizer_ctx *ctx)
1788 {
1789 zend_code_block *next_block = block->next;
1790 uint32_t bitset_len;
1791 zend_bitset usage;
1792 zend_bitset defined_here;
1793 void *checkpoint;
1794
1795 if (op_array->T == 0) {
1796
1797 return;
1798 }
1799
1800 checkpoint = zend_arena_checkpoint(ctx->arena);
1801 bitset_len = zend_bitset_len(op_array->last_var + op_array->T);
1802 usage = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
1803 zend_bitset_clear(usage, bitset_len);
1804 defined_here = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
1805
1806 while (next_block) {
1807 zend_op *opline = next_block->start_opline;
1808 zend_op *end = opline + next_block->len;
1809
1810 if (!next_block->access) {
1811 next_block = next_block->next;
1812 continue;
1813 }
1814 zend_bitset_clear(defined_here, bitset_len);
1815
1816 while (opline<end) {
1817 T_USAGE(opline->op1);
1818 if (opline->op2_type & (IS_VAR | IS_TMP_VAR)) {
1819 if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
1820
1821 zend_bitset_incl(defined_here, VAR_NUM(ZEND_OP2(opline).var));
1822 } else {
1823 T_USAGE(opline->op2);
1824 }
1825 }
1826
1827 if (RESULT_USED(opline)) {
1828 if (!zend_bitset_in(defined_here, VAR_NUM(ZEND_RESULT(opline).var)) && !zend_bitset_in(used_ext, VAR_NUM(ZEND_RESULT(opline).var)) &&
1829 opline->opcode == ZEND_ADD_ARRAY_ELEMENT) {
1830
1831 zend_bitset_incl(used_ext, VAR_NUM(ZEND_RESULT(opline).var));
1832 }
1833 zend_bitset_incl(defined_here, VAR_NUM(ZEND_RESULT(opline).var));
1834 }
1835 opline++;
1836 }
1837 next_block = next_block->next;
1838 }
1839
1840 #if DEBUG_BLOCKPASS
1841 {
1842 int i;
1843 for (i = op_array->last_var; i< op_array->T; i++) {
1844 fprintf(stderr, "T%d: %c\n", i, zend_bitset_in(used_ext, i) + '0');
1845 }
1846 }
1847 #endif
1848
1849 while (block) {
1850 zend_op *opline = block->start_opline + block->len - 1;
1851
1852 if (!block->access) {
1853 block = block->next;
1854 continue;
1855 }
1856
1857 zend_bitset_copy(usage, used_ext, bitset_len);
1858
1859 while (opline >= block->start_opline) {
1860
1861 if (RES_NEVER_USED(opline)) {
1862 switch (opline->opcode) {
1863 case ZEND_ASSIGN_ADD:
1864 case ZEND_ASSIGN_SUB:
1865 case ZEND_ASSIGN_MUL:
1866 case ZEND_ASSIGN_DIV:
1867 case ZEND_ASSIGN_POW:
1868 case ZEND_ASSIGN_MOD:
1869 case ZEND_ASSIGN_SL:
1870 case ZEND_ASSIGN_SR:
1871 case ZEND_ASSIGN_CONCAT:
1872 case ZEND_ASSIGN_BW_OR:
1873 case ZEND_ASSIGN_BW_AND:
1874 case ZEND_ASSIGN_BW_XOR:
1875 case ZEND_PRE_INC:
1876 case ZEND_PRE_DEC:
1877 case ZEND_POST_INC:
1878 case ZEND_POST_DEC:
1879 case ZEND_ASSIGN:
1880 case ZEND_ASSIGN_REF:
1881 case ZEND_DO_FCALL:
1882 case ZEND_DO_ICALL:
1883 case ZEND_DO_UCALL:
1884 case ZEND_DO_FCALL_BY_NAME:
1885 if (ZEND_RESULT_TYPE(opline) == IS_VAR) {
1886 ZEND_RESULT_TYPE(opline) |= EXT_TYPE_UNUSED;
1887 }
1888 break;
1889 case ZEND_QM_ASSIGN:
1890 case ZEND_BOOL:
1891 case ZEND_BOOL_NOT:
1892 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
1893 literal_dtor(&ZEND_OP1_LITERAL(opline));
1894 }
1895 MAKE_NOP(opline);
1896 break;
1897 case ZEND_JMPZ_EX:
1898 case ZEND_JMPNZ_EX:
1899 opline->opcode -= 3;
1900 SET_UNUSED(opline->result);
1901 break;
1902 }
1903 }
1904
1905 if (opline->opcode == ZEND_ADD_ARRAY_ELEMENT) {
1906 if (ZEND_OP1_TYPE(opline) == IS_VAR || ZEND_OP1_TYPE(opline) == IS_TMP_VAR) {
1907 zend_bitset_incl(usage, VAR_NUM(ZEND_RESULT(opline).var));
1908 }
1909 } else {
1910 if (RESULT_USED(opline)) {
1911 zend_bitset_excl(usage, VAR_NUM(ZEND_RESULT(opline).var));
1912 }
1913 }
1914
1915 if (ZEND_OP1_TYPE(opline) == IS_VAR || ZEND_OP1_TYPE(opline) == IS_TMP_VAR) {
1916 zend_bitset_incl(usage, VAR_NUM(ZEND_OP1(opline).var));
1917 }
1918
1919 if (ZEND_OP2_TYPE(opline) == IS_VAR || ZEND_OP2_TYPE(opline) == IS_TMP_VAR) {
1920 zend_bitset_incl(usage, VAR_NUM(ZEND_OP2(opline).var));
1921 }
1922
1923 if ((ZEND_RESULT_TYPE(opline) & IS_VAR) &&
1924 (ZEND_RESULT_TYPE(opline) & EXT_TYPE_UNUSED) &&
1925 zend_bitset_in(usage, VAR_NUM(ZEND_RESULT(opline).var))) {
1926 ZEND_RESULT_TYPE(opline) &= ~EXT_TYPE_UNUSED;
1927 }
1928
1929 opline--;
1930 }
1931 block = block->next;
1932 }
1933
1934 zend_arena_release(&ctx->arena, checkpoint);
1935 }
1936
1937 #define PASSES 3
1938
1939 void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
1940 {
1941 zend_cfg cfg;
1942 zend_code_block *cur_block;
1943 int pass;
1944 uint32_t bitset_len;
1945 zend_bitset usage;
1946 void *checkpoint;
1947
1948 #if DEBUG_BLOCKPASS
1949 fprintf(stderr, "File %s func %s\n", op_array->filename, op_array->function_name? op_array->function_name : "main");
1950 fflush(stderr);
1951 #endif
1952
1953 if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
1954 return;
1955 }
1956
1957
1958 checkpoint = zend_arena_checkpoint(ctx->arena);
1959 if (!find_code_blocks(op_array, &cfg, ctx)) {
1960 zend_arena_release(&ctx->arena, checkpoint);
1961 return;
1962 }
1963
1964 zend_rebuild_access_path(&cfg, op_array, 0, ctx);
1965
1966 if (op_array->last_var || op_array->T) {
1967 bitset_len = zend_bitset_len(op_array->last_var + op_array->T);
1968 cfg.Tsource = zend_arena_calloc(&ctx->arena, op_array->last_var + op_array->T, sizeof(zend_op *));
1969 cfg.same_t = zend_arena_alloc(&ctx->arena, op_array->last_var + op_array->T);
1970 usage = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
1971 } else {
1972 bitset_len = 0;
1973 cfg.Tsource = NULL;
1974 cfg.same_t = NULL;
1975 usage = NULL;
1976 }
1977 for (pass = 0; pass < PASSES; pass++) {
1978
1979 zend_bitset_clear(usage, bitset_len);
1980 zend_t_usage(cfg.blocks, op_array, usage, ctx);
1981
1982
1983 for (cur_block = cfg.blocks; cur_block; cur_block = cur_block->next) {
1984 if (!cur_block->access) {
1985 continue;
1986 }
1987 zend_optimize_block(cur_block, op_array, usage, &cfg, ctx);
1988 }
1989
1990
1991 for (cur_block = cfg.blocks; cur_block; cur_block = cur_block->next) {
1992 if (!cur_block->access) {
1993 continue;
1994 }
1995 zend_jmp_optimization(cur_block, op_array, cfg.blocks, &cfg, ctx);
1996 }
1997
1998
1999 zend_rebuild_access_path(&cfg, op_array, 1, ctx);
2000 }
2001
2002 zend_bitset_clear(usage, bitset_len);
2003 zend_t_usage(cfg.blocks, op_array, usage, ctx);
2004 assemble_code_blocks(&cfg, op_array);
2005
2006
2007 zend_arena_release(&ctx->arena, checkpoint);
2008 }