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