root/eaccelerator/trunk/optimize.c

Revision 425, 120.9 kB (checked in by hans, 4 days ago)

Fix for ticket #432 + some Changelog formatting tweaks

Line 
1 /*
2    +----------------------------------------------------------------------+
3    | eAccelerator project                                                 |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 2004 - 2010 eAccelerator                               |
6    | http://eaccelerator.net                                              |
7    +----------------------------------------------------------------------+
8    | This program is free software; you can redistribute it and/or        |
9    | modify it under the terms of the GNU General Public License          |
10    | as published by the Free Software Foundation; either version 2       |
11    | of the License, or (at your option) any later version.               |
12    |                                                                      |
13    | This program is distributed in the hope that it will be useful,      |
14    | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
15    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
16    | GNU General Public License for more details.                         |
17    |                                                                      |
18    | You should have received a copy of the GNU General Public License    |
19    | along with this program; if not, write to the Free Software          |
20    | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
21    | MA  02111-1307, USA.                                                 |
22    |                                                                      |
23    | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
24    +----------------------------------------------------------------------+
25    $Id$
26 */
27
28 #include "eaccelerator.h"
29
30 #ifdef HAVE_EACCELERATOR
31 #ifdef WITH_EACCELERATOR_OPTIMIZER
32
33 #include "zend.h"
34 #include "zend_API.h"
35 #include "zend_constants.h"
36 #include "opcodes.h"
37
38 #include "debug.h"
39
40 typedef unsigned int* set;
41
42 struct _BBlink;
43
44 typedef struct _BB {
45   zend_op*        start;
46   int             len;
47   int             used;
48   /*
49    * HOESH: To protect merging. Primary
50    * it abblies to try & catch blocks.
51    * ZEND_ENGINE_2 specific, but can take place
52    */
53   int             protect_merge;
54   struct _BB*     jmp_1;
55   struct _BB*     jmp_2;
56   struct _BB*     jmp_ext;
57   struct _BB*     follow;
58   struct _BBlink* pred;  // Gonna be a chain of BBs
59   struct _BB*     next;
60 } BB;
61
62 typedef struct _BBlink {
63   struct _BB*     bb;
64   struct _BBlink* next;
65 } BBlink;
66
67 #ifdef DEBUG
68 static void dump_bb(BB* bb, zend_op_array *op_array) {
69   BB* p = bb;
70   BBlink *q;
71   DBG(ea_debug_printf, (EA_DEBUG, "=== CFG FOR %s:%s ===\n", op_array->filename, op_array->function_name));
72   while (p != NULL) {
73     DBG(ea_debug_printf, (EA_DEBUG, "  bb%u start=%u len=%d used=%d\n",
74                  (unsigned int)(p-bb),
75                  (unsigned int)(p->start-op_array->opcodes),
76                  p->len,
77                  p->used));
78     if (p->jmp_1) {
79       DBG(ea_debug_printf, (EA_DEBUG, "    jmp_1 bb%u start=%u  len=%d used=%d\n",
80                   (unsigned int)(p->jmp_1-bb),
81                   (unsigned int)(p->jmp_1->start-op_array->opcodes),
82                   p->jmp_1->len,
83                   p->jmp_1->used));
84     }
85     if (p->jmp_2) {
86       DBG(ea_debug_printf, (EA_DEBUG, "    jmp_2 bb%u start=%u  len=%d used=%d\n",
87                   (unsigned int)(p->jmp_2-bb),
88                   (unsigned int)(p->jmp_2->start-op_array->opcodes),
89                   p->jmp_2->len,
90                   p->jmp_2->used));
91     }
92     if (p->jmp_ext) {
93       DBG(ea_debug_printf, (EA_DEBUG, "    jmp_ext bb%u start=%u  len=%d used=%d\n",
94                   (unsigned int)(p->jmp_ext-bb),
95                   (unsigned int)(p->jmp_ext->start-op_array->opcodes),
96                   p->jmp_ext->len,
97                   p->jmp_ext->used));
98     }
99     if (p->follow) {
100       DBG(ea_debug_printf, (EA_DEBUG, "    follow bb%u start=%u  len=%d used=%d\n",
101                   (unsigned int)(p->follow-bb),
102                   (unsigned int)(p->follow->start-op_array->opcodes),
103                   p->follow->len,
104                   p->follow->used));
105     }
106     q = p->pred;
107     while (q != NULL) {
108       DBG(ea_debug_printf, (EA_DEBUG, "    pred bb%u start=%u  len=%d used=%d (",
109                   (unsigned int)(q->bb-bb),
110                   (unsigned int)(q->bb->start-op_array->opcodes),
111                   q->bb->len,
112                   q->bb->used));
113       if (q->bb->jmp_1 == p) {
114         DBG(ea_debug_printf, (EA_DEBUG, "jmp_1 "));
115       }
116       if (q->bb->jmp_2 == p) {
117         DBG(ea_debug_printf, (EA_DEBUG, "jmp_2 "));
118       }
119       if (q->bb->jmp_ext == p) {
120         DBG(ea_debug_printf, (EA_DEBUG, "jmp_ext "));
121       }
122       if (q->bb->follow == p) {
123         DBG(ea_debug_printf, (EA_DEBUG, "follow "));
124       }
125       DBG(ea_debug_printf, (EA_DEBUG, ")\n"));
126       q = q->next;
127     }
128     p = p->next;
129   }
130   DBG(ea_debug_printf, (EA_DEBUG, "=== END OF CFG ===========================\n"));
131 }
132
133 static void dump_array(int nb,void *pos,char type)
134 int j;
135
136    switch(type) {
137    case 'i': {
138      int *ptr=pos;
139      for (j=0;j<nb;j++) {
140        zend_printf("%d:%6d ",j,*ptr);
141        ptr++;
142      }
143    }
144    break;
145    case 'x': {
146      int *ptr=pos;
147      for (j=0;j<nb;j++) {
148        zend_printf("%d:%x ",j,*ptr);
149        ptr++;
150      }
151    }
152    break;
153    case 'c': {
154      unsigned char *ptr=pos;
155      for (j=0;j<nb;j++) {
156 /*       if (*ptr>=32 && *ptr<128) zend_printf("%d:%c",j,*ptr);
157        else if (*ptr>=128) zend_printf("%d:%2x",j,*ptr);
158        else if (*ptr<16) zend_printf("%d:&%1x",j,*ptr);
159        else zend_printf("%d:$%1x",j,(*ptr)-16); */
160        zend_printf("%d:%1x ",j,*ptr);
161        ptr++;
162      }
163    }
164    break;   
165    default:
166      for (j=0;j<nb;j++)
167        zend_printf("# ");
168    }
169    zend_printf("<br>\n");
170 }
171 #endif
172
173 #define SET_TO_NOP(op) \
174   (op)->opcode = ZEND_NOP; \
175   (op)->op1.op_type = IS_UNUSED; \
176   (op)->op2.op_type = IS_UNUSED; \
177   (op)->result.op_type = IS_UNUSED;
178
179 static void compute_live_var(BB* bb, zend_op_array* op_array, char* global)
180 {
181   BB* p = bb;
182   char* def;
183   char* used;
184
185 #ifdef ZEND_ENGINE_2_3
186   ALLOCA_FLAG(use_heap)
187 #endif
188
189   memset(global, 0, op_array->T * sizeof(char));
190   if (p != NULL && p->next != NULL) {
191     int bb_count = 0;
192 #ifdef ZEND_ENGINE_2_3
193     def = do_alloca(op_array->T * sizeof(char), use_heap);
194 #else
195     def = do_alloca(op_array->T * sizeof(char));
196 #endif
197 #if 0
198     DBG(ea_debug_printf, (EA_DEBUG, "compute_live_var %s::%s", op_array->filename, op_array->function_name));
199 #endif
200     while (p != NULL) {
201       zend_op* op = p->start;
202       zend_op* end = op + p->len;
203       memset(def, 0, op_array->T * sizeof(char));
204       while (op < end) {
205         if ((op->op1.op_type == IS_VAR || op->op1.op_type == IS_TMP_VAR) &&
206             !def[VAR_NUM(op->op1.u.var)] && !global[VAR_NUM(op->op1.u.var)]) {
207           global[VAR_NUM(op->op1.u.var)] = 1;
208         }
209         if ((op->op2.op_type == IS_VAR || op->op2.op_type == IS_TMP_VAR) &&
210             !def[VAR_NUM(op->op2.u.var)] && !global[VAR_NUM(op->op2.u.var)]) {
211           if (op->opcode != ZEND_OP_DATA) {
212             global[VAR_NUM(op->op2.u.var)] = 1;
213           }
214         }
215 #ifdef ZEND_ENGINE_2_3
216         if ((op->opcode == ZEND_DECLARE_INHERITED_CLASS || op->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) &&
217 #else
218         if (op->opcode == ZEND_DECLARE_INHERITED_CLASS &&
219 #endif
220             !def[VAR_NUM(op->extended_value)] &&
221             !global[VAR_NUM(op->extended_value)]) {
222           global[VAR_NUM(op->extended_value)] = 1;
223         }
224         if ((op->result.op_type == IS_VAR &&
225              (op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT ||
226               (op->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
227             (op->result.op_type == IS_TMP_VAR)) {
228           if (!def[VAR_NUM(op->result.u.var)] && !global[VAR_NUM(op->result.u.var)]) {
229             switch (op->opcode) {
230               case ZEND_RECV:
231               case ZEND_RECV_INIT:
232               case ZEND_ADD_ARRAY_ELEMENT:
233                 global[VAR_NUM(op->result.u.var)] = 1;
234              }
235           }
236           def[VAR_NUM(op->result.u.var)] = 1;
237         }
238         op++;
239       }
240       p = p->next;
241       bb_count++;
242     }
243 #ifdef ZEND_ENGINE_2_3
244     free_alloca(def, use_heap);
245 #else
246     free_alloca(def);
247 #endif
248   }
249 #ifdef ZEND_ENGINE_2_3
250     used = do_alloca(op_array->T * sizeof(char), use_heap);
251 #else
252     used = do_alloca(op_array->T * sizeof(char));
253 #endif
254     p = bb;
255     while (p != NULL) {
256       zend_op* op = p->start;
257       zend_op* end = op + p->len;
258       memset(used, 0, op_array->T * sizeof(char));
259       while (op < end) {
260         end--;
261         if (((end->result.op_type == IS_VAR &&
262              (end->opcode == ZEND_RECV || end->opcode == ZEND_RECV_INIT ||
263               (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
264              (end->result.op_type == IS_TMP_VAR)) &&
265             !global[VAR_NUM(end->result.u.var)] && !used[VAR_NUM(end->result.u.var)]) {
266            switch(end->opcode) {
267              case ZEND_JMPZ_EX:
268                end->opcode = ZEND_JMPZ;
269                end->result.op_type = IS_UNUSED;
270                break;
271              case ZEND_JMPNZ_EX:
272                end->opcode = ZEND_JMPNZ;
273                end->result.op_type = IS_UNUSED;
274                break;
275              case ZEND_ASSIGN_ADD:
276              case ZEND_ASSIGN_SUB:
277              case ZEND_ASSIGN_MUL:
278              case ZEND_ASSIGN_DIV:
279              case ZEND_ASSIGN_MOD:
280              case ZEND_ASSIGN_SL:
281              case ZEND_ASSIGN_SR:
282              case ZEND_ASSIGN_CONCAT:
283              case ZEND_ASSIGN_BW_OR:
284              case ZEND_ASSIGN_BW_AND:
285              case ZEND_ASSIGN_BW_XOR:
286              case ZEND_PRE_INC:
287              case ZEND_PRE_DEC:
288              case ZEND_POST_INC:
289              case ZEND_POST_DEC:
290              case ZEND_ASSIGN:
291              case ZEND_ASSIGN_REF:
292              case ZEND_DO_FCALL:
293              case ZEND_DO_FCALL_BY_NAME:
294                if (end->result.op_type == IS_VAR) {
295                  end->result.u.EA.type |= EXT_TYPE_UNUSED;
296                }
297                break;
298              case ZEND_UNSET_VAR:
299              case ZEND_UNSET_DIM:
300              case ZEND_UNSET_OBJ:
301                end->result.op_type = IS_UNUSED;
302                break;
303              case ZEND_RECV:
304              case ZEND_RECV_INIT:
305              case ZEND_INCLUDE_OR_EVAL:
306              case ZEND_NEW:
307              case ZEND_FE_FETCH:
308              case ZEND_PRINT:
309              case ZEND_INIT_METHOD_CALL:
310              case ZEND_INIT_STATIC_METHOD_CALL:
311              case ZEND_ASSIGN_DIM:
312              case ZEND_ASSIGN_OBJ:
313              case ZEND_DECLARE_CLASS:
314              case ZEND_DECLARE_INHERITED_CLASS:
315 #ifdef ZEND_DECLARE_INHERITED_CLASS_DELAYED
316              case ZEND_DECLARE_INHERITED_CLASS_DELAYED:
317 #endif
318               break;
319             default:
320               if (end->op1.op_type == IS_CONST) {
321                 zval_dtor(&end->op1.u.constant);
322               }
323               if (end->op2.op_type == IS_CONST) {
324                 zval_dtor(&end->op2.u.constant);
325               }
326               SET_TO_NOP(end);
327           }
328         } else if (end->result.op_type == IS_VAR &&
329                    (end->result.u.EA.type & EXT_TYPE_UNUSED) != 0 &&
330                    end->opcode != ZEND_RECV && end->opcode != ZEND_RECV_INIT &&
331                    used[VAR_NUM(end->result.u.var)]) {
332           end->result.u.EA.type &= ~EXT_TYPE_UNUSED;
333         }
334         if ((end->result.op_type == IS_VAR &&
335             (end->opcode == ZEND_RECV || end->opcode == ZEND_RECV_INIT ||
336              (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
337             (end->result.op_type == IS_TMP_VAR)) {
338           switch (end->opcode) {
339             case ZEND_RECV:
340             case ZEND_RECV_INIT:
341             case ZEND_ADD_ARRAY_ELEMENT:
342               used[VAR_NUM(end->result.u.var)] = 1;
343               break;
344             default:
345               used[VAR_NUM(end->result.u.var)] = 0;
346            }
347         }
348         if (end->op1.op_type == IS_VAR || end->op1.op_type == IS_TMP_VAR) {
349           used[VAR_NUM(end->op1.u.var)] = 1;
350         }
351         if (end->op2.op_type == IS_VAR || end->op2.op_type == IS_TMP_VAR) {
352           used[VAR_NUM(end->op2.u.var)] = 1;
353         }
354 #ifdef ZEND_ENGINE_2_3
355         if (end->opcode == ZEND_DECLARE_INHERITED_CLASS || end->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
356 #else
357         if (end->opcode == ZEND_DECLARE_INHERITED_CLASS) {
358 #endif
359           used[VAR_NUM(end->extended_value)] = 1;
360         }
361       }
362       p = p->next;
363     }
364 #ifdef ZEND_ENGINE_2_3
365     free_alloca(used, use_heap);
366 #else
367     free_alloca(used);
368 #endif
369 }
370
371 /* Adds FROM as predecessor of TO */
372 #define BB_ADD_PRED(TO,FROM) { \
373                                BBlink *q = (TO)->pred; \
374                                while (q != NULL) { \
375                                  if (q->bb == (FROM)) break; \
376                                  q = q->next; \
377                                } \
378                                if (q == NULL) { \
379                                  q = emalloc(sizeof(*q)); \
380                                  q->bb = (FROM); \
381                                  q->next = (TO)->pred; \
382                                  (TO)->pred = q; \
383                                } \
384                              }
385
386 /* Removes FROM from predecessors of TO */
387 #define BB_DEL_PRED(TO,FROM) { \
388                                BBlink *q = (TO)->pred; \
389                                if (q != NULL) { \
390                                  if (q->bb == (FROM)) { \
391                                    (TO)->pred = q->next; \
392                                    efree(q); \
393                                  } else { \
394                                    while (q->next != NULL) { \
395                                      if (q->next->bb == (FROM)) { \
396                                        BBlink *r = q->next; \
397                                        q->next = q->next->next; \
398                                        efree(r); \
399                                        break; \
400                                      } \
401                                      q = q->next; \
402                                    } \
403                                  } \
404                                } \
405                              }
406
407 #define RM_BB(p) do {if (p->pred == NULL && p != bb) rm_bb(p);} while (0)
408
409 static void mark_used_bb(BB* bb)
410 {
411   if (bb->used) return;
412   bb->used = 1;
413   if (bb->jmp_1 != NULL) {
414     mark_used_bb(bb->jmp_1);
415     BB_ADD_PRED(bb->jmp_1, bb);
416   }
417   if (bb->jmp_2 != NULL) {
418     mark_used_bb(bb->jmp_2);
419     BB_ADD_PRED(bb->jmp_2, bb);
420   }
421   if (bb->jmp_ext != NULL) {
422     mark_used_bb(bb->jmp_ext);
423     BB_ADD_PRED(bb->jmp_ext, bb);
424   }
425   if (bb->follow != NULL) {
426     mark_used_bb(bb->follow);
427     BB_ADD_PRED(bb->follow, bb);
428   }
429 }
430
431 static void mark_used_bb2(BB* bb)
432 {
433   if (bb->used) return;
434   bb->used = 1;
435   if (bb->jmp_1 != NULL) {
436     mark_used_bb2(bb->jmp_1);
437   }
438   if (bb->jmp_2 != NULL) {
439     mark_used_bb2(bb->jmp_2);
440   }
441   if (bb->jmp_ext != NULL) {
442     mark_used_bb2(bb->jmp_ext);
443   }
444   if (bb->follow != NULL) {
445     mark_used_bb2(bb->follow);
446   }
447 }
448
449 static void rm_bb(BB* bb)
450 {
451   if (bb->used == 0) {
452     return;
453   }
454   bb->used = 0;
455   if (bb->jmp_1 != NULL) {
456     BB_DEL_PRED(bb->jmp_1, bb);
457   }
458   if (bb->jmp_2 != NULL) {
459     BB_DEL_PRED(bb->jmp_2, bb);
460   }
461   if (bb->jmp_ext != NULL) {
462     BB_DEL_PRED(bb->jmp_ext, bb);
463   }
464   if (bb->follow != NULL) {
465     BB_DEL_PRED(bb->follow, bb);
466   }
467 }
468
469 static void del_bb(BB* bb)
470 {
471   zend_op* op = bb->start;
472   zend_op* end = op + bb->len;
473
474   rm_bb(bb);
475   while (op < end) {
476     --end;
477     if (end->op1.op_type == IS_CONST) {
478       zval_dtor(&end->op1.u.constant);
479     }
480     if (end->op2.op_type == IS_CONST) {
481       zval_dtor(&end->op2.u.constant);
482     }
483     SET_TO_NOP(end);
484   }
485   bb->len  = 0;
486   bb->used = 0;
487 }
488 /*
489 static void replace_bb(BB* src, BB* dst)
490 {
491   BBlink* p = src->pred;
492   while (p != NULL) {
493     BBlink* q = p->next;
494     if (p->bb->jmp_1   == src) {
495       p->bb->jmp_1 = dst;
496       BB_ADD_PRED(dst,p->bb);
497     }
498     if (p->bb->jmp_2   == src) {
499       p->bb->jmp_2 = dst;
500       BB_ADD_PRED(dst,p->bb);
501     }
502     if (p->bb->jmp_ext == src) {
503       p->bb->jmp_ext = dst;
504       BB_ADD_PRED(dst,p->bb);
505     }
506     if (p->bb->follow  == src) {
507       p->bb->follow = dst;
508       BB_ADD_PRED(dst,p->bb);
509     }
510     efree(p);
511     p = q;
512   }
513   src->pred = NULL;
514 }
515 */
516 static void optimize_jmp(BB* bb, zend_op_array* op_array)
517 {
518   BB* p;
519
520   while(1) {
521     int ok = 1;
522
523     /* Remove Unused Basic Blocks */
524     p = bb;
525     while (p->next != NULL) {
526       if (p->next->used && p->next->pred) {
527         p = p->next;
528       } else {
529         del_bb(p->next);
530         p->next = p->next->next;
531         ok = 0;
532       }
533     }
534
535     /* JMP optimization */
536     p = bb;
537     while (p != NULL) {
538       while (p->next != NULL && (!p->next->used || p->next->pred == NULL)) {
539         del_bb(p->next);
540         p->next = p->next->next;
541         ok = 0;
542       }
543       if (p->used && p->len > 0) {
544         zend_op* op = &p->start[p->len-1];
545
546         switch (op->opcode) {
547           case ZEND_JMP:
548 jmp:
549             /* L1: JMP L1+1  => NOP
550             */
551             if (p->jmp_1 == p->next) {
552               if (p->follow) {
553                 BB_DEL_PRED(p->follow, p);
554               }
555               p->follow = p->jmp_1;
556               p->jmp_1   = NULL;
557               SET_TO_NOP(op);
558               --(p->len);
559               ok = 0;
560               break;
561             }
562             /*     JMP L1  =>  JMP L2
563                    ...         ...
564                L1: JMP L2      JMP L2
565             */
566             while (p->jmp_1->len == 1 &&
567                 p->jmp_1->start->opcode == ZEND_JMP &&
568                 p->jmp_1 != p) {
569               BB* x_p = p->jmp_1;
570               BB_DEL_PRED(p->jmp_1, p);
571               RM_BB(x_p);
572               p->jmp_1 = x_p->jmp_1;
573               BB_ADD_PRED(p->jmp_1, p);
574               ok = 0;
575             }
576             break;
577           case ZEND_JMPZNZ:
578 jmp_znz:
579             /* JMPZNZ  ?,L1,L1  =>  JMP L1
580             */
581             if (p->jmp_ext == p->jmp_2) {
582               op->opcode = ZEND_JMP;
583               op->extended_value = 0;
584               op->op1.op_type = IS_UNUSED;
585               op->op2.op_type = IS_UNUSED;
586               p->jmp_1 = p->jmp_2;
587               p->jmp_2 = NULL;
588               p->jmp_ext = NULL;
589               ok = 0;
590               goto jmp;
591             } else if (op->op1.op_type == IS_CONST) {
592               /* JMPZNZ  0,L1,L2  =>  JMP L1
593               */
594               if (!zend_is_true(&op->op1.u.constant)) {
595                 op->opcode = ZEND_JMP;
596                 op->extended_value = 0;
597                 op->op1.op_type = IS_UNUSED;
598                 op->op2.op_type = IS_UNUSED;
599                 if (p->jmp_ext != p->jmp_2) {
600                   BB_DEL_PRED(p->jmp_ext, p);
601                   RM_BB(p->jmp_ext);
602                 }
603                 p->jmp_1   = p->jmp_2;
604                 p->jmp_2   = NULL;
605                 p->jmp_ext = NULL;
606                 p->follow  = NULL;
607                 ok = 0;
608                 goto jmp;
609               /* JMPZNZ  1,L1,L2  =>  JMP L2
610               */
611               } else {
612                 op->opcode = ZEND_JMP;
613                 op->extended_value = 0;
614                 op->op1.op_type = IS_UNUSED;
615                 op->op2.op_type = IS_UNUSED;
616                 if (p->jmp_ext != p->jmp_2) {
617                   BB_DEL_PRED(p->jmp_2, p);
618                   RM_BB(p->jmp_2);
619                 }
620                 p->jmp_1   = p->jmp_ext;
621                 p->jmp_2   = NULL;
622                 p->jmp_ext = NULL;
623                 p->follow  = NULL;
624                 ok = 0;
625                 goto jmp;
626               }
627             /* L1: JMPZNZ ?,L2,L1+1  => JMPZ ?,L2
628             */
629             } else if (p->jmp_ext == p->next) {
630               op->opcode = ZEND_JMPZ;
631               op->extended_value = 0;
632               p->follow = p->jmp_ext;
633               p->jmp_ext = NULL;
634               ok = 0;
635               goto jmp_z;
636             /* L1: JMPZNZ ?,L1+1,L2  => JMPNZ ?,L2
637             */
638             } else if (p->jmp_2 == p->next) {
639               op->opcode = ZEND_JMPNZ;
640               op->extended_value = 0;
641               p->follow = p->jmp_2;
642               p->jmp_2  = p->jmp_ext;
643               p->jmp_ext = NULL;
644               ok = 0;
645               goto jmp_nz;
646             } else if (p->jmp_2->len == 1 &&
647                        op->op1.op_type == IS_TMP_VAR) {
648             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L3,L2
649                    ...                  ...
650                L1: JMPZ   $x,L3         JMPZ   $x,L3
651             */
652             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L3,L2
653                    ...                  ...
654                L1: JMPZNZ $x,L3,L4      JMPZNZ $x,L3,L4
655             */
656             if        ((p->jmp_2->start->opcode == ZEND_JMPZ ||
657                         p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
658                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
659                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
660               if (p->jmp_2 != p->jmp_ext) {
661                 BB_DEL_PRED(p->jmp_2, p);
662                 RM_BB(p->jmp_2);
663               }
664               p->jmp_2 = p->jmp_2->jmp_2;
665               BB_ADD_PRED(p->jmp_2, p);
666               ok = 0;
667               goto jmp_znz;
668             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1+1,L2
669                    ...                  ...
670                L1: JMPNZ  $x,L3         JMPNZ  $x,L3
671             */
672             } else if (p->jmp_2->start->opcode == ZEND_JMPNZ &&
673                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
674                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
675               if (p->jmp_2 != p->jmp_ext) {
676                 BB_DEL_PRED(p->jmp_2, p);
677                 RM_BB(p->jmp_2);
678               }
679               p->jmp_2 = p->jmp_2->follow;
680               BB_ADD_PRED(p->jmp_2, p);
681               ok = 0;
682               goto jmp_znz;
683             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L3
684                    ...                  ...
685                L2: JMPNZ  $x,L3         JMPNZ  $x,L3
686             */
687             } else if (p->jmp_ext->start->opcode == ZEND_JMPNZ &&
688                        p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
689                        op->op1.u.var == p->jmp_ext->start->op1.u.var) {
690               if (p->jmp_2 != p->jmp_ext) {
691                 BB_DEL_PRED(p->jmp_ext, p);
692                 RM_BB(p->jmp_ext);
693               }
694               p->jmp_ext = p->jmp_ext->jmp_2;
695               BB_ADD_PRED(p->jmp_ext, p);
696               ok = 0;
697               goto jmp_znz;
698             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L4
699                    ...                  ...
700                L2: JMPZNZ $x,L3,L4      JMPZNZ $x,L3,L4
701             */
702             } else if (p->jmp_ext->start->opcode == ZEND_JMPZNZ &&
703                        p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
704                        op->op1.u.var == p->jmp_ext->start->op1.u.var) {
705               if (p->jmp_2 != p->jmp_ext) {
706                 BB_DEL_PRED(p->jmp_ext, p);
707                 RM_BB(p->jmp_ext);
708               }
709               p->jmp_ext = p->jmp_ext->jmp_ext;
710               BB_ADD_PRED(p->jmp_ext, p);
711               ok = 0;
712               goto jmp_znz;
713             /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L2+1
714                    ...                  ...
715                L2: JMPZ   $x,L3         JMPZ   $x,L3
716             */
717             } else if (p->jmp_ext->start->opcode == ZEND_JMPZ &&
718                        p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
719                        op->op1.u.var == p->jmp_ext->start->op1.u.var) {
720               if (p->jmp_2 != p->jmp_ext) {
721                 BB_DEL_PRED(p->jmp_ext, p);
722                 RM_BB(p->jmp_ext);
723               }
724               p->jmp_ext = p->jmp_ext->follow;
725               BB_ADD_PRED(p->jmp_ext, p);
726               ok = 0;
727               goto jmp_znz;
728             }
729             }
730             while (p->jmp_2->len == 1 && p->jmp_2->start->opcode == ZEND_JMP) {
731               BB* x_p = p->jmp_2;
732               if (p->jmp_2 != p->jmp_ext) {
733                 BB_DEL_PRED(p->jmp_2, p);
734                 RM_BB(x_p);
735               }
736               p->jmp_2 = x_p->jmp_1;
737               BB_ADD_PRED(p->jmp_2, p);
738               ok = 0;
739             }
740             while (p->jmp_ext->len == 1 && p->jmp_ext->start->opcode == ZEND_JMP) {
741               BB* x_p = p->jmp_ext;
742               if (p->jmp_2 != p->jmp_ext) {
743                 BB_DEL_PRED(p->jmp_ext, p);
744                 RM_BB(x_p);
745               }
746               p->jmp_ext = x_p->jmp_1;
747               BB_ADD_PRED(p->jmp_ext, p);
748               ok = 0;
749             }
750             break;
751           case ZEND_JMPZ:
752 jmp_z:
753             /* L1: JMPZ  ?,L1+1  =>  NOP
754             */
755             if (p->follow == p->jmp_2) {
756               p->jmp_2   = NULL;
757               SET_TO_NOP(op);
758               --(p->len);
759               ok = 0;
760               break;
761             } else if (op->op1.op_type == IS_CONST) {
762               /* JMPZ  0,L1  =>  JMP L1
763               */
764               if (!zend_is_true(&op->op1.u.constant)) {
765                 op->opcode = ZEND_JMP;
766                 op->op1.op_type = IS_UNUSED;
767                 op->op2.op_type = IS_UNUSED;
768                 if (p->follow != p->jmp_2) {
769                   BB_DEL_PRED(p->follow, p);
770                   RM_BB(p->follow);
771                 }
772                 p->jmp_1  = p->jmp_2;
773                 p->jmp_2  = NULL;
774                 p->follow = NULL;
775                 ok = 0;
776                 goto jmp;
777               /* JMPZ  1,L1  =>  NOP
778               */
779               } else {
780                 if (p->follow != p->jmp_2) {
781                   BB_DEL_PRED(p->jmp_2, p);
782                   RM_BB(p->jmp_2);
783                 }
784                 p->jmp_2   = NULL;
785                 SET_TO_NOP(op);
786                 --(p->len);
787                 ok = 0;
788                 break;
789               }
790             /* JMPZ ?,L1  =>  JMPZNZ  ?,L1,L2
791                JMP  L2        JMP     L2
792             */
793             } else if (p->follow->len == 1 && p->follow->start->opcode == ZEND_JMP) {
794               BB* x_p = p->follow;
795               op->opcode = ZEND_JMPZNZ;
796               if (p->jmp_2 != p->follow) {
797                 BB_DEL_PRED(p->follow, p);
798                 RM_BB(x_p);
799               }
800               p->follow = NULL;
801               p->jmp_ext = x_p->jmp_1;
802               BB_ADD_PRED(p->jmp_ext, p);
803               ok = 0;
804               goto jmp_znz;
805             } else if (p->jmp_2->len == 1 &&
806                        op->op1.op_type == IS_TMP_VAR) {
807             /*     JMPZ $x,L1  =>  JMPZ $x,L2
808                    ...             ...
809                L1: JMPZ $x,L2      JMPZ $x,L2
810                ----------------------------------------
811                    JMPZ   $x,L1     =>  JMPZ  $x,L2
812                    ...                   ...
813                L1: JMPZNZ $x,L2,L3      JMPZNZ $x,L2,L3
814             */
815             if       ((p->jmp_2->start->opcode == ZEND_JMPZ ||
816                        p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
817                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
818                       op->op1.u.var == p->jmp_2->start->op1.u.var) {
819               if (p->jmp_2 != p->follow) {
820                 BB_DEL_PRED(p->jmp_2, p);
821                 RM_BB(p->jmp_2);
822               }
823               p->jmp_2 = p->jmp_2->jmp_2;
824               BB_ADD_PRED(p->jmp_2, p);
825               ok = 0;
826               goto jmp_z;
827             /*     JMPZ  $x,L1  =>  JMPZ  $x,L1+1
828                    ...              ...
829                L1: JMPNZ $x,L2      JMPNZ $x,L2
830             */
831             } else if (p->jmp_2->start->opcode == ZEND_JMPNZ &&
832                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
833                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
834               if (p->jmp_2 != p->follow) {
835                 BB_DEL_PRED(p->jmp_2, p);
836                 RM_BB(p->jmp_2);
837               }
838               p->jmp_2 = p->jmp_2->follow;
839               BB_ADD_PRED(p->jmp_2, p);
840               ok = 0;
841               goto jmp_z;
842             }
843             }
844             goto jmp_2;
845           case ZEND_JMPNZ:
846 jmp_nz:
847             /* L1: JMPNZ  ?,L1+1  =>  NOP
848             */
849             if (p->follow == p->jmp_2) {
850               p->jmp_2   = NULL;
851               SET_TO_NOP(op);
852               --(p->len);
853               ok = 0;
854               break;
855             } else if (op->op1.op_type == IS_CONST) {
856               /* JMPNZ  1,L1  =>  JMP L1
857               */
858               if (zend_is_true(&op->op1.u.constant)) {
859                 op->opcode = ZEND_JMP;
860                 op->op1.op_type = IS_UNUSED;
861                 op->op2.op_type = IS_UNUSED;
862                 if (p->follow != p->jmp_2) {
863                   BB_DEL_PRED(p->follow, p);
864                   RM_BB(p->follow);
865                 }
866                 p->jmp_1  = p->jmp_2;
867                 p->jmp_2  = NULL;
868                 p->follow = NULL;
869                 ok = 0;
870                 goto jmp;
871               /* JMPNZ  0,L1  =>  NOP
872               */
873               } else {
874                 if (p->follow != p->jmp_2) {
875                   BB_DEL_PRED(p->jmp_2, p);
876                   RM_BB(p->jmp_2);
877                 }
878                 p->jmp_2   = NULL;
879                 SET_TO_NOP(op);
880                 --(p->len);
881                 ok = 0;
882                 break;
883               }
884             /* JMPNZ ?,L1  =>  JMPZNZ  ?,L2,L1
885                JMP   L2        JMP     L2
886             */
887             } else if (p->follow->len == 1 && p->follow->start->opcode == ZEND_JMP) {
888               BB* x_p = p->follow;
889               op->opcode = ZEND_JMPZNZ;
890               if (p->jmp_2 != p->follow) {
891                 BB_DEL_PRED(p->follow, p);
892                 RM_BB(p->follow);
893               }
894               p->follow = NULL;
895               p->jmp_ext = p->jmp_2;
896               p->jmp_2 = x_p->jmp_1;
897               BB_ADD_PRED(p->jmp_2, p);
898               ok = 0;
899               goto jmp_znz;
900             /*     JMPNZ $x,L1  =>  JMPNZ $x,L2
901                    ...              ...
902                L1: JMPNZ $x,L2      JMPNZ $x,L2
903             */
904             } else if (p->jmp_2->len == 1 &&
905                        op->op1.op_type == IS_TMP_VAR) {
906             if        (p->jmp_2->start->opcode == ZEND_JMPNZ &&
907                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
908                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
909               if (p->jmp_2 != p->follow) {
910                 BB_DEL_PRED(p->jmp_2, p);
911                 RM_BB(p->jmp_2);
912               }
913               p->jmp_2 = p->jmp_2->jmp_2;
914               BB_ADD_PRED(p->jmp_2, p);
915               ok = 0;
916               goto jmp_nz;
917             /*     JMPNZ  $x,L1  =>  JMPNZ  $x,L1+1
918                    ...               ...
919                L1: JMPZ   $x,L2      JMPZ $x,L2
920             */
921             } else if (p->jmp_2->start->opcode == ZEND_JMPZ &&
922                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
923                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
924               if (p->jmp_2 != p->follow) {
925                 BB_DEL_PRED(p->jmp_2, p);
926                 RM_BB(p->jmp_2);
927               }
928               p->jmp_2 = p->jmp_2->follow;
929               BB_ADD_PRED(p->jmp_2, p);
930               ok = 0;
931               goto jmp_nz;
932             /*     JMPNZ  $x,L1     =>  JMPNZ  $x,L3
933                    ...                   ...
934                L1: JMPZNZ $x,L2,L3      JMPZNZ $x,L2,L3
935             */
936             } else if (p->jmp_2->start->opcode == ZEND_JMPZNZ &&
937                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
938                        op->op1.u.var == p->jmp_2->start->op1.u.var) {
939               if (p->jmp_2 != p->follow) {
940                 BB_DEL_PRED(p->jmp_2, p);
941                 RM_BB(p->jmp_2);
942               }
943               p->jmp_2 = p->jmp_2->jmp_ext;
944               BB_ADD_PRED(p->jmp_2, p);
945               ok = 0;
946               goto jmp_nz;
947             }
948             }
949             goto jmp_2;
950           case ZEND_JMPZ_EX:
951 jmp_z_ex:
952             /* L1: JMPZ_EX  $x,L1+1,$x  =>  NOP
953             */
954             if (p->follow == p->jmp_2 &&
955                 op->op1.op_type == IS_TMP_VAR &&
956                 op->result.op_type == IS_TMP_VAR &&
957                 op->op1.u.var == op->result.u.var) {
958               p->jmp_2   = NULL;
959               SET_TO_NOP(op);
960               --(p->len);
961               ok = 0;
962               break;
963             /* L1: JMPZ_EX  $x,L1+1,$y  =>  BOOL $x,$y
964             */
965             } else if (p->follow == p->jmp_2) {
966               p->jmp_2   = NULL;
967               op->opcode = ZEND_BOOL;
968               op->op2.op_type = IS_UNUSED;
969               ok = 0;
970               break;
971             } else if (p->jmp_2->len == 1 &&
972                        op->result.op_type == IS_TMP_VAR) {
973             /*     JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
974                    ...                  ...
975                L1: JMPZ    $x,L2        JMPZ    $x,L2
976                ------------------------------------------
977                    JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
978                    ...                  ...
979                L1: JMPZNZ  $x,L2,L3     JMPZNZ  $x,L2,L3
980                ------------------------------------------
981                    JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
982                    ...                  ...
983                L1: JMPZ_EX $x,L2,$x     JMPZ_EX $x,L2,$x
984             */
985             if       (((p->jmp_2->start->opcode == ZEND_JMPZ ||
986                          p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
987                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
988                         op->result.u.var == p->jmp_2->start->op1.u.var) ||
989                        (p->jmp_2->start->opcode == ZEND_JMPZ_EX &&
990                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
991                         p->jmp_2->start->result.op_type == IS_TMP_VAR &&
992                         op->result.u.var == p->jmp_2->start->op1.u.var &&
993                         op->result.u.var == p->jmp_2->start->result.u.var)) {
994               if (p->jmp_2 != p->follow) {
995                 BB_DEL_PRED(p->jmp_2, p);
996                 RM_BB(p->jmp_2);
997               }
998               p->jmp_2 = p->jmp_2->jmp_2;
999               BB_ADD_PRED(p->jmp_2, p);
1000               ok = 0;
1001               goto jmp_z_ex;
1002             /*     JMPZ_EX ?,L1,$x   =>  JMPZ_EX ?,L2+1,$x
1003                    ...                   ...
1004                L1: JMPNZ    $x,L2        JMPNZ    $x,L2
1005                ------------------------------------------
1006                    JMPZ_EX ?,L1,$x   =>  JMPZ_EX  ?,L2+1,$x
1007                    ...                   ...
1008                L1: JMPNZ_EX $x,L2,$x     JMPNZ_EX $x,L2,$x
1009             */
1010             } else if ((p->jmp_2->start->opcode == ZEND_JMPNZ &&
1011                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1012                         op->result.u.var == p->jmp_2->start->op1.u.var) ||
1013                        (p->jmp_2->start->opcode == ZEND_JMPNZ_EX &&
1014                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1015                         p->jmp_2->start->result.op_type == IS_TMP_VAR &&
1016                         op->result.u.var == p->jmp_2->start->op1.u.var &&
1017                         op->result.u.var == p->jmp_2->start->result.u.var)) {
1018               if (p->jmp_2 != p->follow) {
1019                 BB_DEL_PRED(p->jmp_2, p);
1020                 RM_BB(p->jmp_2);
1021               }
1022               p->jmp_2 = p->jmp_2->follow;
1023               BB_ADD_PRED(p->jmp_2, p);
1024               ok = 0;
1025               goto jmp_z_ex;
1026             /*     JMPZ_EX ?,L1,$x   =>  JMPZ_EX ?,L1+1,$y
1027                    ...                   ...
1028                L1: BOOL    $x,$y         BOOL    $x,$y
1029             */
1030             } else if (p->jmp_2->start->opcode == ZEND_BOOL &&
1031                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1032                        op->result.u.var == p->jmp_2->start->op1.u.var) {
1033               memcpy(&op->result, &p->jmp_2->start->result, sizeof(zval));
1034               if (p->jmp_2 != p->follow) {
1035                 BB_DEL_PRED(p->jmp_2, p);
1036                 RM_BB(p->jmp_2);
1037               }
1038               p->jmp_2 = p->jmp_2->follow;
1039               BB_ADD_PRED(p->jmp_2, p);
1040               ok = 0;
1041               goto jmp_z_ex;
1042             /*     JMPZ_EX ?,L1,$x   =>  JMPZ    ?,L1+1
1043                    ...                   ...
1044                L1: FREE    $x            FREE    $x
1045             */
1046             } else if (p->jmp_2->start->opcode == ZEND_FREE &&
1047                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1048                        op->result.u.var == p->jmp_2->start->op1.u.var) {
1049               op->opcode = ZEND_JMPZ;
1050               op->result.op_type = IS_UNUSED;
1051               if (p->jmp_2 != p->follow) {
1052                 BB_DEL_PRED(p->jmp_2, p);
1053                 RM_BB(p->jmp_2);
1054               }
1055               p->jmp_2 = p->jmp_2->follow;
1056               BB_ADD_PRED(p->jmp_2, p);
1057               ok = 0;
1058               goto jmp_z;
1059             }
1060             /*     JMPZ_EX ?,L1,$x   =>  JMPZ ?,L1+1
1061                    ...                   ...
1062                L1: FREE    $x            FREE $x
1063             */
1064             } else if (op->result.op_type == IS_TMP_VAR &&
1065                        p->jmp_2->start->opcode == ZEND_FREE &&
1066                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1067                        op->result.u.var == p->jmp_2->start->op1.u.var) {
1068               if (p->jmp_2->len > 1) {
1069                 /* splitting */
1070                 BB* new_bb = (p->jmp_2+1);
1071                 new_bb->used   = 1;
1072                 new_bb->start  = p->jmp_2->start+1;
1073                 new_bb->len    = p->jmp_2->len-1;
1074                 p->jmp_2->len  = 1;
1075                 new_bb->next   = p->jmp_2->next;
1076                 p->jmp_2->next = new_bb;
1077                 new_bb->pred   = NULL;
1078                 if (p->jmp_2->jmp_1) {
1079                   new_bb->jmp_1     = p->jmp_2->jmp_1;
1080                   BB_ADD_PRED(new_bb->jmp_1, new_bb);
1081                   BB_DEL_PRED(new_bb->jmp_1, p->jmp_2);
1082                   p->jmp_2->jmp_1   = NULL;
1083                 }
1084                 if (p->jmp_2->jmp_2) {
1085                   new_bb->jmp_2     = p->jmp_2->jmp_2;
1086                   BB_ADD_PRED(new_bb->jmp_2, new_bb);
1087                   BB_DEL_PRED(new_bb->jmp_2, p->jmp_2);
1088                   p->jmp_2->jmp_2   = NULL;
1089                 }
1090                 if (p->jmp_2->jmp_ext) {
1091                   new_bb->jmp_ext     = p->jmp_2->jmp_ext;
1092                   BB_ADD_PRED(new_bb->jmp_ext, new_bb);
1093                   BB_DEL_PRED(new_bb->jmp_ext, p->jmp_2);
1094                   p->jmp_2->jmp_ext   = NULL;
1095                 }
1096                 op->opcode = ZEND_JMPZ;
1097                 op->result.op_type = IS_UNUSED;
1098                 if (p->jmp_2->follow) {
1099                   new_bb->follow     = p->jmp_2->follow;
1100                   BB_ADD_PRED(new_bb->follow, new_bb);
1101                   BB_DEL_PRED(new_bb->follow, p->jmp_2);
1102                   p->jmp_2->follow   = NULL;
1103                 }
1104                 p->jmp_2->follow = new_bb;
1105                 BB_ADD_PRED(p->jmp_2->follow, p->jmp_2);
1106               }
1107               if (p->jmp_2 != p->follow) {
1108                 BB_DEL_PRED(p->jmp_2, p);
1109                 RM_BB(p->jmp_2);
1110               }
1111               p->jmp_2 = p->jmp_2->follow;
1112               BB_ADD_PRED(p->jmp_2, p);
1113               ok = 0;
1114               goto jmp_z;
1115             }
1116             goto jmp_2;
1117           case ZEND_JMPNZ_EX:
1118 jmp_nz_ex:
1119             /* L1: JMPNZ_EX  $x,L1+1,$x  =>  NOP
1120             */
1121             if (p->follow == p->jmp_2 &&
1122                 op->op1.op_type == IS_TMP_VAR &&
1123                 op->result.op_type == IS_TMP_VAR &&
1124                 op->op1.u.var == op->result.u.var) {
1125               p->jmp_2   = NULL;
1126               SET_TO_NOP(op);
1127               --(p->len);
1128               ok = 0;
1129               break;
1130             /* L1: JMPNZ_EX  $x,L1+1,$y  =>  BOOL $x,$y
1131             */
1132             } else if (p->follow == p->jmp_2) {
1133               p->jmp_2   = NULL;
1134               op->opcode = ZEND_BOOL;
1135               op->op2.op_type = IS_UNUSED;
1136               ok = 0;
1137               break;
1138             } else if (p->jmp_2->len == 1 &&
1139                        op->result.op_type == IS_TMP_VAR) {
1140             /*     JMPNZ_EX ?,L1,$x  =>  JMPNZ_EX ?,L2,$x
1141                    ...                   ...
1142                L1: JMPNZ    $x,L2        JMPNZ    $x,L2
1143                ------------------------------------------
1144                    JMPNZ_EX ?,L1,$x  =>  JMPNZ_EX ?,L2,$x
1145                    ...                   ...
1146                L1: JMPNZ_EX $x,L2,$x     JMPNZ_EX $x,L2,$x
1147             */
1148             if        ((p->jmp_2->start->opcode == ZEND_JMPNZ &&
1149                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1150                         op->result.u.var == p->jmp_2->start->op1.u.var) ||
1151                        (p->jmp_2->start->opcode == ZEND_JMPNZ_EX &&
1152                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1153                         p->jmp_2->start->result.op_type == IS_TMP_VAR &&
1154                         op->result.u.var == p->jmp_2->start->op1.u.var &&
1155                         op->result.u.var == p->jmp_2->start->result.u.var)) {
1156               if (p->jmp_2 != p->follow) {
1157                 BB_DEL_PRED(p->jmp_2, p);
1158                 RM_BB(p->jmp_2);
1159               }
1160               p->jmp_2 = p->jmp_2->jmp_2;
1161               BB_ADD_PRED(p->jmp_2, p);
1162               ok = 0;
1163               goto jmp_nz_ex;
1164             /*     JMPNZ_EX ?,L1,$x   =>  JMPNZ_EX ?,L3,$x
1165                    ...                    ...
1166                L1: JMPZNZ   $x,L2,L3      JMPZNZ   $x,L2,L3
1167             */
1168             } else if (p->jmp_2->start->opcode == ZEND_JMPZNZ &&
1169                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1170                        op->result.u.var == p->jmp_2->start->op1.u.var) {
1171               if (p->jmp_2 != p->follow) {
1172                 BB_DEL_PRED(p->jmp_2, p);
1173                 RM_BB(p->jmp_2);
1174               }
1175               p->jmp_2 = p->jmp_2->jmp_ext;
1176               BB_ADD_PRED(p->jmp_2, p);
1177               ok = 0;
1178               goto jmp_nz_ex;
1179             /*     JMPNZ_EX ?,L1,$x   =>  JMPNZ_EX ?,L1+1,$x
1180                    ...                    ...
1181                L1: JMPZ    $x,L2          JMPZ    $x,L2
1182                ------------------------------------------
1183                    JMPNZ_EX ?,L1,$x   =>  JMPNZ_EX  ?,L1+1,$x
1184                    ...                    ...
1185                L1: JMPZ_EX $x,L2,$x      JMPZ_EX $x,L2,$x
1186             */
1187             } else if ((p->jmp_2->start->opcode == ZEND_JMPZ &&
1188                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1189                         op->result.u.var == p->jmp_2->start->op1.u.var) ||
1190                        (p->jmp_2->start->opcode == ZEND_JMPZ_EX &&
1191                         p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1192                         p->jmp_2->start->result.op_type == IS_TMP_VAR &&
1193                         op->result.u.var == p->jmp_2->start->op1.u.var &&
1194                         op->result.u.var == p->jmp_2->start->result.u.var)) {
1195               if (p->jmp_2 != p->follow) {
1196                 BB_DEL_PRED(p->jmp_2, p);
1197                 RM_BB(p->jmp_2);
1198               }
1199               p->jmp_2 = p->jmp_2->follow;
1200               BB_ADD_PRED(p->jmp_2, p);
1201               ok = 0;
1202               goto jmp_nz_ex;
1203             /*     JMPNZ_EX ?,L1,$x   =>  JMPNZ_EX ?,L1+1,$y
1204                    ...                   ...
1205                L1: BOOL    $x,$y         BOOL    $x,$y
1206             */
1207             } else if (p->jmp_2->start->opcode == ZEND_BOOL &&
1208                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1209                        op->result.u.var == p->jmp_2->start->op1.u.var) {
1210               memcpy(&op->result, &p->jmp_2->start->result, sizeof(zval));
1211               if (p->jmp_2 != p->follow) {
1212                 BB_DEL_PRED(p->jmp_2, p);
1213                 RM_BB(p->jmp_2);
1214               }
1215               p->jmp_2 = p->jmp_2->follow;
1216               BB_ADD_PRED(p->jmp_2, p);
1217               ok = 0;
1218               goto jmp_nz_ex;
1219             /*     JMPNZ_EX ?,L1,$x   =>  JMPNZ ?,L1+1
1220                    ...                    ...
1221                L1: FREE    $x             FREE    $x
1222             */
1223             } else if (p->jmp_2->start->opcode == ZEND_FREE &&
1224                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1225                        op->result.u.var == p->jmp_2->start->op1.u.var) {
1226               op->opcode = ZEND_JMPNZ;
1227               op->result.op_type = IS_UNUSED;
1228               if (p->jmp_2 != p->follow) {
1229                 BB_DEL_PRED(p->jmp_2, p);
1230                 RM_BB(p->jmp_2);
1231               }
1232               p->jmp_2 = p->jmp_2->follow;
1233               BB_ADD_PRED(p->jmp_2, p);
1234               ok = 0;
1235               goto jmp_nz;
1236             }
1237             /*     JMPNZ_EX ?,L1,$x   =>  JMPNZ_EX ?,L1+1,$x
1238                    ...                    ...
1239                L1: FREE    $x             FREE    $x
1240             */
1241             } else if (op->result.op_type == IS_TMP_VAR &&
1242                        p->jmp_2->start->opcode == ZEND_FREE &&
1243                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
1244                        op->result.u.var == p->jmp_2->start->op1.u.var) {
1245               if (p->jmp_2->len > 1) {
1246                 /* splitting */
1247                 BB* new_bb = (p->jmp_2+1);
1248                 new_bb->used   = 1;
1249                 new_bb->start  = p->jmp_2->start+1;
1250                 new_bb->len    = p->jmp_2->len-1;
1251                 p->jmp_2->len  = 1;
1252                 new_bb->next   = p->jmp_2->next;
1253                 p->jmp_2->next = new_bb;
1254                 new_bb->pred   = NULL;
1255                 if (p->jmp_2->jmp_1) {
1256                   new_bb->jmp_1     = p->jmp_2->jmp_1;
1257                   BB_ADD_PRED(new_bb->jmp_1, new_bb);
1258                   BB_DEL_PRED(new_bb->jmp_1, p->jmp_2);
1259                   p->jmp_2->jmp_1   = NULL;
1260                 }
1261                 if (p->jmp_2->jmp_2) {
1262                   new_bb->jmp_2     = p->jmp_2->jmp_2;
1263                   BB_ADD_PRED(new_bb->jmp_2, new_bb);
1264                   BB_DEL_PRED(new_bb->jmp_2, p->jmp_2);
1265                   p->jmp_2->jmp_2   = NULL;
1266                 }
1267                 if (p->jmp_2->jmp_ext) {
1268                   new_bb->jmp_ext     = p->jmp_2->jmp_ext;
1269                   BB_ADD_PRED(new_bb->jmp_ext, new_bb);
1270                   BB_DEL_PRED(new_bb->jmp_ext, p->jmp_2);
1271                   p->jmp_2->jmp_ext   = NULL;
1272                 }
1273                 if (p->jmp_2->follow) {
1274                   new_bb->follow     = p->jmp_2->follow;
1275                   BB_ADD_PRED(new_bb->follow, new_bb);
1276                   BB_DEL_PRED(new_bb->follow, p->jmp_2);
1277                   p->jmp_2->follow   = NULL;
1278                 }
1279                 p->jmp_2->follow = new_bb;
1280                 BB_ADD_PRED(p->jmp_2->follow, p->jmp_2);
1281               }
1282               op->opcode = ZEND_JMPNZ;
1283               op->result.op_type = IS_UNUSED;
1284               if (p->jmp_2 != p->follow) {
1285                 BB_DEL_PRED(p->jmp_2, p);
1286                 RM_BB(p->jmp_2);
1287               }
1288               p->jmp_2 = p->jmp_2->follow;
1289               BB_ADD_PRED(p->jmp_2, p);
1290               ok = 0;
1291               goto jmp_nz;
1292             }
1293             goto jmp_2;
1294           case ZEND_NEW:
1295           case ZEND_FE_FETCH:
1296 jmp_2:
1297             while (p->jmp_2->len == 1 && p->jmp_2->start->opcode == ZEND_JMP) {
1298               BB* x_p = p->jmp_2;
1299               if (p->jmp_2 != p->follow) {
1300                 BB_DEL_PRED(p->jmp_2, p);
1301                 RM_BB(x_p);
1302               }
1303               p->jmp_2 = x_p->jmp_1;
1304               BB_ADD_PRED(p->jmp_2, p);
1305               ok = 0;
1306             }
1307         }
1308       }
1309
1310       /* Merging Basic Blocks */
1311       if (p->used && p->pred != NULL && p->pred->bb->used && p->pred->next == NULL &&
1312           p->pred->bb->follow == p &&
1313           p->pred->bb->next == p &&
1314           p->pred->bb->jmp_1 == NULL &&
1315           p->pred->bb->jmp_2 == NULL &&
1316           p->pred->bb->jmp_ext == NULL &&
1317                   /* HOESH: See structure declaration */
1318                   p->protect_merge == 0)
1319           {
1320         BB* x = p->pred->bb;
1321         BB_DEL_PRED(p, x);
1322         x->len = &p->start[p->len] - x->start;
1323         if (p->jmp_1 != NULL) {
1324           x->jmp_1 = p->jmp_1;
1325           BB_DEL_PRED(p->jmp_1, p);
1326           BB_ADD_PRED(p->jmp_1, x);
1327         }
1328         if (p->jmp_2 != NULL) {
1329           x->jmp_2   = p->jmp_2;
1330           BB_DEL_PRED(p->jmp_2, p);
1331           BB_ADD_PRED(p->jmp_2, x);
1332         }
1333         if (p->jmp_ext != NULL) {
1334           x->jmp_ext   = p->jmp_ext;
1335           BB_DEL_PRED(p->jmp_ext, p);
1336           BB_ADD_PRED(p->jmp_ext, x);
1337         }
1338         x->follow  = p->follow;
1339         if (p->follow != NULL) {
1340           BB_DEL_PRED(p->follow, p);
1341           BB_ADD_PRED(p->follow, x);
1342         }
1343         p->used  = 0;
1344         p->len   = 0;
1345         ok = 0;
1346       }
1347
1348       p = p->next;
1349     }
1350
1351     if (ok) {
1352       /* Eliminate JMP to RETURN or EXIT */
1353       p = bb;
1354       while (p != NULL) {
1355         if (p->used && p->len > 0) {
1356           zend_op* op = &p->start[p->len-1];
1357           if (op->opcode == ZEND_JMP &&
1358               p->jmp_1->len == 1 &&
1359               (p->jmp_1->start->opcode == ZEND_RETURN ||
1360                p->jmp_1->start->opcode == ZEND_EXIT))
1361                   {
1362                     if (op->extended_value == ZEND_BRK || op->extended_value == ZEND_CONT) {
1363               op->extended_value = 0;
1364                     } else {
1365               BB_DEL_PRED(p->jmp_1, p);
1366               RM_BB(p->jmp_1);
1367               memcpy(op, p->jmp_1->start, sizeof(zend_op));
1368               if (op->op1.op_type == IS_CONST)
1369                           {
1370                 zval_copy_ctor(&op->op1.u.constant);
1371               }
1372               p->jmp_1 = NULL;
1373               ok = 0;
1374             }
1375           }
1376         }
1377         p = p->next;
1378       }
1379     }
1380     if (ok) {
1381       break;
1382     }
1383   }
1384 }
1385
1386 static int opt_get_constant(const char* name, int name_len, zend_constant** result TSRMLS_DC) {
1387   union {
1388     zend_constant *v;
1389     void *ptr;
1390   } c;
1391   int retval;
1392 #ifdef ZEND_ENGINE_2_3
1393   ALLOCA_FLAG(use_heap)
1394   char *lookup_name = do_alloca(name_len+1, use_heap);
1395 #else
1396   char *lookup_name = do_alloca(name_len+1);
1397 #endif
1398   memcpy(lookup_name, name, name_len);
1399   lookup_name[name_len] = '\0';
1400
1401   if (zend_hash_find(EG(zend_constants), lookup_name, name_len+1, &c.ptr)==SUCCESS) {
1402     *result = c.v;
1403     retval=1;
1404   } else {
1405     zend_str_tolower(lookup_name, name_len);
1406
1407     if (zend_hash_find(EG(zend_constants), lookup_name, name_len+1, &c.ptr)==SUCCESS) {
1408       if ((c.v->flags & CONST_CS) && (memcmp(c.v->name, name, name_len)!=0)) {
1409         retval=0;
1410       } else {
1411         *result = c.v;
1412         retval=1;
1413       }
1414     } else {
1415       retval=0;
1416     }
1417   }
1418 #ifdef ZEND_ENGINE_2_3
1419   free_alloca(lookup_name, use_heap);
1420 #else
1421   free_alloca(lookup_name);
1422 #endif
1423   return retval;
1424 }
1425
1426 static int opt_function_exists(const char* name, int name_len TSRMLS_DC) {
1427   char *lcname;
1428   char *lcfname;
1429   Bucket *p;
1430
1431   lcname = estrndup(name,name_len+1);
1432   zend_str_tolower(lcname, name_len);
1433   p = module_registry.pListHead;
1434   while (p != NULL) {
1435     zend_module_entry *m = (zend_module_entry*)p->pData;
1436     if (m->type == MODULE_PERSISTENT) {
1437 #ifdef ZEND_ENGINE_2_3
1438       const zend_function_entry* f = m->functions;
1439 #else
1440       zend_function_entry* f = m->functions;
1441 #endif
1442       if (f != NULL) {
1443         while (f->fname) {
1444         lcfname = estrdup(f->fname);
1445         zend_str_tolower(lcfname, strlen(lcfname));
1446         if (strcmp(lcname,lcfname) == 0) {
1447           efree(lcfname);
1448           efree(lcname);
1449           return 1;
1450         }
1451           efree(lcfname);
1452           f++;
1453         }
1454       }
1455     }
1456     p = p->pListNext;
1457   }
1458   efree(lcname);
1459   return 0;
1460 }
1461
1462 static int opt_extension_loaded(const char* name, int name_len TSRMLS_DC) {
1463   Bucket *p = module_registry.pListHead;
1464   while (p != NULL) {
1465     zend_module_entry *m = (zend_module_entry*)p->pData;
1466     if (m->type == MODULE_PERSISTENT && strcmp(m->name,name) == 0) {
1467       return 1;
1468     }
1469     p = p->pListNext;
1470   }
1471   return 0;
1472 }
1473
1474 static int opt_result_is_numeric(zend_op* x) {
1475   switch (x->opcode) {
1476     case ZEND_ADD:
1477     case ZEND_SUB:
1478     case ZEND_MUL:
1479     case ZEND_DIV:
1480     case ZEND_MOD:
1481     case ZEND_SL:
1482     case ZEND_SR:
1483     case ZEND_BOOL:
1484     case ZEND_BOOL_NOT:
1485     case ZEND_BOOL_XOR:
1486     case ZEND_IS_IDENTICAL:
1487     case ZEND_IS_NOT_IDENTICAL:
1488     case ZEND_IS_EQUAL:
1489     case ZEND_IS_NOT_EQUAL:
1490     case ZEND_IS_SMALLER:
1491     case ZEND_IS_SMALLER_OR_EQUAL:
1492     case ZEND_PRE_DEC:
1493     case ZEND_PRE_INC:
1494     case ZEND_POST_DEC:
1495     case ZEND_POST_INC:
1496     case ZEND_ASSIGN_ADD:
1497     case ZEND_ASSIGN_SUB:
1498     case ZEND_ASSIGN_MUL:
1499     case ZEND_ASSIGN_DIV:
1500     case ZEND_ASSIGN_MOD:
1501     case ZEND_ASSIGN_SL:
1502     case ZEND_ASSIGN_SR:
1503       return 1;
1504     case ZEND_CAST:
1505       if (x->extended_value == IS_BOOL ||
1506           x->extended_value == IS_LONG ||
1507           x->extended_value == IS_DOUBLE) {
1508         return 1;
1509       }
1510       return 0;
1511     case ZEND_DO_FCALL:
1512       /* list generated in ext/standard with:
1513          grep "proto int" *| awk '{ print $5}'|sed -r 's/^(.+)\((.*)/\1/'|sort -u
1514          + some function aliases and other frequently used funcs
1515       */
1516       if (x->op1.op_type == IS_CONST &&
1517           x->op1.u.constant.type == IS_STRING &&
1518           (strcmp(x->op1.u.constant.value.str.val,"abs") == 0 ||
1519            strcmp(x->op1.u.constant.value.str.val,"array_push") == 0 ||
1520            strcmp(x->op1.u.constant.value.str.val,"array_unshift") == 0 ||
1521            strcmp(x->op1.u.constant.value.str.val,"assert") == 0 ||
1522            strcmp(x->op1.u.constant.value.str.val,"bindec") == 0 ||
1523            strcmp(x->op1.u.constant.value.str.val,"connection_aborted") == 0 ||
1524            strcmp(x->op1.u.constant.value.str.val,"connection_status") == 0 ||
1525            strcmp(x->op1.u.constant.value.str.val,"count") == 0 ||
1526            strcmp(x->op1.u.constant.value.str.val,"dl") == 0 ||
1527            strcmp(x->op1.u.constant.value.str.val,"extract") == 0 ||
1528            strcmp(x->op1.u.constant.value.str.val,"ezmlm_hash") == 0 ||
1529            strcmp(x->op1.u.constant.value.str.val,"file_put_contents") == 0 ||
1530            strcmp(x->op1.u.constant.value.str.val,"fileatime") == 0 ||
1531            strcmp(x->op1.u.constant.value.str.val,"filectime") == 0 ||
1532            strcmp(x->op1.u.constant.value.str.val,"filegroup") == 0 ||
1533            strcmp(x->op1.u.constant.value.str.val,"fileinode") == 0 ||
1534            strcmp(x->op1.u.constant.value.str.val,"filemtime") == 0 ||
1535            strcmp(x->op1.u.constant.value.str.val,"fileowner") == 0 ||
1536            strcmp(x->op1.u.constant.value.str.val,"fileperms") == 0 ||
1537            strcmp(x->op1.u.constant.value.str.val,"filesize") == 0 ||
1538            strcmp(x->op1.u.constant.value.str.val,"fpassthru") == 0 ||
1539            strcmp(x->op1.u.constant.value.str.val,"fprintf") == 0 ||
1540            strcmp(x->op1.u.constant.value.str.val,"fputcsv") == 0 ||
1541            strcmp(x->op1.u.constant.value.str.val,"fseek") == 0 ||
1542            strcmp(x->op1.u.constant.value.str.val,"ftell") == 0 ||
1543            strcmp(x->op1.u.constant.value.str.val,"ftok") == 0 ||
1544            strcmp(x->op1.u.constant.value.str.val,"fwrite") == 0 ||
1545            strcmp(x->op1.u.constant.value.str.val,"get_magic_quotes_gpc") == 0 ||
1546            strcmp(x->op1.u.constant.value.str.val,"get_magic_quotes_runtime") == 0 ||
1547            strcmp(x->op1.u.constant.value.str.val,"getlastmod") == 0 ||
1548            strcmp(x->op1.u.constant.value.str.val,"getmygid") == 0 ||
1549            strcmp(x->op1.u.constant.value.str.val,"getmyinode") == 0 ||
1550            strcmp(x->op1.u.constant.value.str.val,"getmypid") == 0 ||
1551            strcmp(x->op1.u.constant.value.str.val,"getmyuid") == 0 ||
1552            strcmp(x->op1.u.constant.value.str.val,"getprotobyname") == 0 ||
1553            strcmp(x->op1.u.constant.value.str.val,"getrandmax") == 0 ||
1554            strcmp(x->op1.u.constant.value.str.val,"getservbyname") == 0 ||
1555            strcmp(x->op1.u.constant.value.str.val,"hexdec") == 0 ||
1556            strcmp(x->op1.u.constant.value.str.val,"ignore_user_abort") == 0 ||
1557            strcmp(x->op1.u.constant.value.str.val,"intval") == 0 ||
1558            strcmp(x->op1.u.constant.value.str.val,"ip2long") == 0 ||
1559            strcmp(x->op1.u.constant.value.str.val,"levenshtein") == 0 ||
1560            strcmp(x->op1.u.constant.value.str.val,"link") == 0 ||
1561            strcmp(x->op1.u.constant.value.str.val,"linkinfo") == 0 ||
1562            strcmp(x->op1.u.constant.value.str.val,"mail") == 0 ||
1563            strcmp(x->op1.u.constant.value.str.val,"memory_get_peak_usage") == 0 ||
1564            strcmp(x->op1.u.constant.value.str.val,"memory_get_usage") == 0 ||
1565            strcmp(x->op1.u.constant.value.str.val,"mt_getrandmax") == 0 ||
1566            strcmp(x->op1.u.constant.value.str.val,"mt_rand") == 0 ||
1567            strcmp(x->op1.u.constant.value.str.val,"octdec") == 0 ||
1568            strcmp(x->op1.u.constant.value.str.val,"ord") == 0 ||
1569            strcmp(x->op1.u.constant.value.str.val,"pclose") == 0 ||
1570            strcmp(x->op1.u.constant.value.str.val,"printf") == 0 ||
1571            strcmp(x->op1.u.constant.value.str.val,"proc_close") == 0 ||
1572            strcmp(x->op1.u.constant.value.str.val,"rand") == 0 ||
1573            strcmp(x->op1.u.constant.value.str.val,"readfile") == 0 ||
1574            strcmp(x->op1.u.constant.value.str.val,"similar_text") == 0 ||
1575            strcmp(x->op1.u.constant.value.str.val,"strcasecmp") == 0 ||
1576            strcmp(x->op1.u.constant.value.str.val,"strcoll") == 0 ||
1577            strcmp(x->op1.u.constant.value.str.val,"strcmp") == 0 ||
1578            strcmp(x->op1.u.constant.value.str.val,"strcspn") == 0 ||
1579            strcmp(x->op1.u.constant.value.str.val,"stream_select") == 0 ||
1580            strcmp(x->op1.u.constant.value.str.val,"stream_set_write_buffer") == 0 ||
1581            strcmp(x->op1.u.constant.value.str.val,"stream_socket_enable_crypto") == 0 ||
1582            strcmp(x->op1.u.constant.value.str.val,"stream_socket_shutdown") == 0 ||
1583            strcmp(x->op1.u.constant.value.str.val,"stripos") == 0 ||
1584            strcmp(x->op1.u.constant.value.str.val,"strlen") == 0 ||
1585            strcmp(x->op1.u.constant.value.str.val,"strnatcasecmp") == 0 ||
1586            strcmp(x->op1.u.constant.value.str.val,"strnatcmp") == 0 ||
1587            strcmp(x->op1.u.constant.value.str.val,"strncmp") == 0 ||
1588            strcmp(x->op1.u.constant.value.str.val,"strpos") == 0 ||
1589            strcmp(x->op1.u.constant.value.str.val,"strripos") == 0 ||
1590            strcmp(x->op1.u.constant.value.str.val,"strrpos") == 0 ||
1591            strcmp(x->op1.u.constant.value.str.val,"strspn") == 0 ||
1592            strcmp(x->op1.u.constant.value.str.val,"substr_compare") == 0 ||
1593            strcmp(x->op1.u.constant.value.str.val,"substr_count") == 0 ||
1594            strcmp(x->op1.u.constant.value.str.val,"symlink") == 0 ||
1595            strcmp(x->op1.u.constant.value.str.val,"system") == 0 ||
1596            strcmp(x->op1.u.constant.value.str.val,"umask") == 0 ||
1597            strcmp(x->op1.u.constant.value.str.val,"version_compare") == 0 ||
1598            strcmp(x->op1.u.constant.value.str.val,"vfprintf") == 0 ||
1599            strcmp(x->op1.u.constant.value.str.val,"vprintf") == 0 ||
1600            strcmp(x->op1.u.constant.value.str.val,"fputs") == 0 ||              /* func alias of fwrite */
1601            strcmp(x->op1.u.constant.value.str.val,"set_file_buffer") == 0 ||    /* func alias of stream_set_write_buffer */
1602            strcmp(x->op1.u.constant.value.str.val,"sizeof") == 0 ||             /* func alias of count */
1603            strcmp(x->op1.u.constant.value.str.val,"ereg") == 0 ||
1604            strcmp(x->op1.u.constant.value.str.val,"eregi") == 0)) {
1605         return 1;
1606       }
1607       return 0;
1608     default:
1609       return 0;
1610   }
1611   return 0;
1612 }
1613
1614 #define FETCH_TYPE(op) ((op)->op2.u.EA.type)
1615 #define SET_UNDEFINED(op) Ts[VAR_NUM((op).u.var)] = NULL;
1616 #define SET_DEFINED(op)   Ts[VAR_NUM((op)->result.u.var)] = (op);
1617 #define IS_DEFINED(op)    (Ts[VAR_NUM((op).u.var)] != NULL)
1618 #define DEFINED_OP(op)    (Ts[VAR_NUM((op).u.var)])
1619
1620 static void optimize_bb(BB* bb, zend_op_array* op_array, char* global, int pass TSRMLS_DC)
1621 {
1622   zend_op* prev = NULL;
1623   zend_op* op = bb->start;
1624   zend_op* end = op + bb->len;
1625
1626   HashTable assigns;
1627   HashTable fetch_dim;
1628
1629 #ifdef ZEND_ENGINE_2_3
1630   ALLOCA_FLAG(use_heap)
1631   zend_op** Ts = do_alloca(sizeof(zend_op*)*op_array->T, use_heap);
1632 #else
1633   zend_op** Ts = do_alloca(sizeof(zend_op*)*op_array->T);
1634 #endif
1635   memset(Ts, 0, sizeof(zend_op*)*op_array->T);
1636
1637   zend_hash_init(&assigns, 0, NULL, NULL, 0);
1638   zend_hash_init(&fetch_dim, 0, NULL, NULL, 0);
1639
1640   while (op < end) {
1641     /* Constant Folding */
1642     if (op->op1.op_type == IS_TMP_VAR &&
1643         IS_DEFINED(op->op1) &&
1644         DEFINED_OP(op->op1)->opcode == ZEND_QM_ASSIGN &&
1645         DEFINED_OP(op->op1)->op1.op_type == IS_CONST) {
1646       zend_op *x = DEFINED_OP(op->op1);
1647       if (op->opcode != ZEND_CASE) {
1648         SET_UNDEFINED(op->op1);
1649         memcpy(&op->op1, &x->op1, sizeof(znode));
1650         SET_TO_NOP(x);
1651       }
1652     }
1653     if (op->op2.op_type == IS_TMP_VAR &&
1654         IS_DEFINED(op->op2) &&
1655         DEFINED_OP(op->op2)->opcode == ZEND_QM_ASSIGN &&
1656         DEFINED_OP(op->op2)->op1.op_type == IS_CONST) {
1657       zend_op *x = DEFINED_OP(op->op2);
1658       SET_UNDEFINED(op->op2);
1659       memcpy(&op->op2, &x->op1, sizeof(znode));
1660       SET_TO_NOP(x);
1661     }
1662
1663     if (op->opcode == ZEND_IS_EQUAL) {
1664       if (op->op1.op_type == IS_CONST &&
1665           (op->op1.u.constant.type == IS_BOOL &&
1666            op->op1.u.constant.value.lval == 0)) {
1667         op->opcode = ZEND_BOOL_NOT;
1668         memcpy(&op->op1, &op->op2, sizeof(znode));
1669         op->op2.op_type = IS_UNUSED;
1670       } else if (op->op1.op_type == IS_CONST &&
1671                  op->op1.u.constant.type == IS_BOOL &&
1672                  op->op1.u.constant.value.lval == 1) {
1673         op->opcode = ZEND_BOOL;
1674         memcpy(&op->op1, &op->op2, sizeof(znode));
1675         op->op2.op_type = IS_UNUSED;
1676       } else if (op->op2.op_type == IS_CONST &&
1677                  op->op2.u.constant.type == IS_BOOL &&
1678                  op->op2.u.constant.value.lval == 0) {
1679         op->opcode = ZEND_BOOL_NOT;
1680         op->op2.op_type = IS_UNUSED;
1681       } else if (op->op2.op_type == IS_CONST &&
1682           op->op2.u.constant.type == IS_BOOL &&
1683           op->op2.u.constant.value.lval == 1) {
1684         op->opcode = ZEND_BOOL;
1685         op->op2.op_type = IS_UNUSED;
1686       } else if (op->op2.op_type == IS_CONST &&
1687           op->op2.u.constant.type == IS_LONG &&
1688           op->op2.u.constant.value.lval == 0 &&
1689           (op->op1.op_type == IS_TMP_VAR || op->op1.op_type == IS_VAR) &&
1690           IS_DEFINED(op->op1) &&
1691           opt_result_is_numeric(DEFINED_OP(op->op1))) {
1692         op->opcode = ZEND_BOOL_NOT;
1693         op->op2.op_type = IS_UNUSED;
1694       }
1695     } else if (op->opcode == ZEND_IS_NOT_EQUAL) {
1696       if (op->op1.op_type == IS_CONST &&
1697           op->op1.u.constant.type == IS_BOOL &&
1698           op->op1.u.constant.value.lval == 0) {
1699         op->opcode = ZEND_BOOL;
1700         memcpy(&op->op1, &op->op2, sizeof(znode));
1701         op->op2.op_type = IS_UNUSED;
1702       } else if (op->op1.op_type == IS_CONST &&
1703                  op->op1.u.constant.type == IS_BOOL &&
1704                  op->op1.u.constant.value.lval == 1) {
1705         op->opcode = ZEND_BOOL_NOT;
1706         memcpy(&op->op1, &op->op2, sizeof(znode));
1707         op->op2.op_type = IS_UNUSED;
1708       } else if (op->op2.op_type == IS_CONST &&
1709                  op->op2.u.constant.type == IS_BOOL &&
1710                  op->op2.u.constant.value.lval == 0) {
1711         op->opcode = ZEND_BOOL;
1712         op->op2.op_type = IS_UNUSED;
1713       } else if (op->op2.op_type == IS_CONST &&
1714           op->op2.u.constant.type == IS_BOOL &&
1715           op->op2.u.constant.value.lval == 1) {
1716         op->opcode = ZEND_BOOL_NOT;
1717         op->op2.op_type = IS_UNUSED;
1718       } else if (op->op2.op_type == IS_CONST &&
1719           op->op2.u.constant.type == IS_LONG &&
1720           op->op2.u.constant.value.lval == 0 &&
1721           (op->op1.op_type == IS_TMP_VAR || op->op1.op_type == IS_VAR) &&
1722           IS_DEFINED(op->op1) &&
1723           opt_result_is_numeric(DEFINED_OP(op->op1))) {
1724         op->opcode = ZEND_BOOL;
1725         op->op2.op_type = IS_UNUSED;
1726       }
1727     }
1728
1729     if ((op->opcode == ZEND_ADD ||
1730                 op->opcode == ZEND_SUB ||
1731                 op->opcode == ZEND_MUL ||
1732                 op->opcode == ZEND_DIV ||
1733                 op->opcode == ZEND_MOD ||
1734                 op->opcode == ZEND_SL ||
1735                 op->opcode == ZEND_SR ||
1736                 op->opcode == ZEND_CONCAT ||
1737                 op->opcode == ZEND_BW_OR ||
1738                 op->opcode == ZEND_BW_AND ||
1739                 op->opcode == ZEND_BW_XOR ||
1740                 op->opcode == ZEND_BOOL_XOR ||
1741                 op->opcode == ZEND_IS_IDENTICAL ||
1742                 op->opcode == ZEND_IS_NOT_IDENTICAL ||
1743                 op->opcode == ZEND_IS_EQUAL ||
1744                 op->opcode == ZEND_IS_NOT_EQUAL ||
1745                 op->opcode == ZEND_IS_SMALLER ||
1746                 op->opcode == ZEND_IS_SMALLER_OR_EQUAL) &&
1747                op->op1.op_type == IS_CONST &&
1748                op->op2.op_type == IS_CONST &&
1749                op->result.op_type == IS_TMP_VAR) {
1750
1751       typedef int (*binary_op_type)(zval *, zval *, zval*  TSRMLS_DC);
1752
1753       binary_op_type binary_op = (binary_op_type)get_binary_op(op->opcode);
1754
1755       if (binary_op != NULL) {
1756         int old = EG(error_reporting);
1757         zval res;
1758         EG(error_reporting) = 0;
1759         if (binary_op(&res, &op->op1.u.constant, &op->op2.u.constant TSRMLS_CC) != FAILURE) {
1760           zval_dtor(&op->op1.u.constant);
1761           zval_dtor(&op->op2.u.constant);
1762           op->opcode = ZEND_QM_ASSIGN;
1763           op->extended_value = 0;
1764           op->op1.op_type = IS_CONST;
1765           memcpy(&op->op1.u.constant, &res, sizeof(zval));
1766           op->op2.op_type = IS_UNUSED;
1767         }
1768         EG(error_reporting) = old;
1769       }
1770     } else if ((op->opcode == ZEND_BW_NOT ||
1771                 op->opcode == ZEND_BOOL_NOT) &&
1772                op->op1.op_type == IS_CONST &&
1773                op->result.op_type == IS_TMP_VAR) {
1774       int (*unary_op)(zval *result, zval *op1) =
1775         unary_op = get_unary_op(op->opcode);
1776       if (unary_op != NULL) {
1777         int old = EG(error_reporting);
1778         zval res;
1779         EG(error_reporting) = 0;
1780         if (unary_op(&res, &op->op1.u.constant) != FAILURE) {
1781           zval_dtor(&op->op1.u.constant);
1782           op->opcode = ZEND_QM_ASSIGN;
1783           op->extended_value = 0;
1784           op->op1.op_type = IS_CONST;
1785           memcpy(&op->op1.u.constant, &res, sizeof(zval));
1786           op->op2.op_type = IS_UNUSED;
1787         }
1788         EG(error_reporting) = old;
1789       }
1790     } else if ((op->opcode == ZEND_BOOL) &&
1791                op->op1.op_type == IS_CONST &&
1792                op->result.op_type == IS_TMP_VAR) {
1793       zval res;
1794       res.type = IS_BOOL;
1795       res.value.lval = zend_is_true(&op->op1.u.constant);
1796       zval_dtor(&op->op1.u.constant);
1797       op->opcode = ZEND_QM_ASSIGN;
1798       op->extended_value = 0;
1799       op->op1.op_type = IS_CONST;
1800       memcpy(&op->op1.u.constant, &res, sizeof(zval));
1801       op->op2.op_type = IS_UNUSED;
1802     } else if ((op->opcode == ZEND_CAST) &&
1803                op->op1.op_type == IS_CONST &&
1804                op->result.op_type == IS_TMP_VAR &&
1805                op->extended_value != IS_ARRAY &&
1806                op->extended_value != IS_OBJECT &&
1807                op->extended_value != IS_RESOURCE) {
1808       zval res;
1809       memcpy(&res,&op->op1.u.constant,sizeof(zval));
1810       zval_copy_ctor(&res);
1811       switch (op->extended_value) {
1812         case IS_NULL:
1813           convert_to_null(&res);
1814           break;
1815         case IS_BOOL:
1816           convert_to_boolean(&res);
1817           break;
1818         case IS_LONG:
1819           convert_to_long(&res);
1820           break;
1821         case IS_DOUBLE:
1822           convert_to_double(&res);
1823           break;
1824         case IS_STRING:
1825           convert_to_string(&res);
1826           break;
1827         case IS_ARRAY:
1828           convert_to_array(&res);
1829           break;
1830         case IS_OBJECT:
1831           convert_to_object(&res);
1832           break;
1833       }
1834       zval_dtor(&op->op1.u.constant);
1835       op->opcode = ZEND_QM_ASSIGN;
1836       op->extended_value = 0;
1837       op->op1.op_type = IS_CONST;
1838       memcpy(&op->op1.u.constant, &res, sizeof(zval));
1839       op->op2.op_type = IS_UNUSED;
1840
1841     /* FREE(CONST) => NOP
1842     */
1843     } else if (op->opcode == ZEND_FREE &&
1844                op->op1.op_type == IS_CONST) {
1845       zval_dtor(&op->op1.u.constant);
1846       SET_TO_NOP(op);
1847
1848     /* INIT_STRING ADD_CHAR ADD_STRING ADD_VAR folding */
1849
1850     /* INIT_STRING($y) => QM_ASSIGN('',$y)
1851     */
1852     } else if (op->opcode == ZEND_INIT_STRING) {
1853       op->opcode = ZEND_QM_ASSIGN;
1854       op->op1.op_type = IS_CONST;
1855       op->op2.op_type = IS_UNUSED;
1856       op->op1.u.constant.type = IS_STRING;
1857       op->op1.u.constant.value.str.len = 0;
1858       op->op1.u.constant.value.str.val = empty_string;
1859     /* ADD_CHAR(CONST,CONST,$y) => QM_ASSIGN(CONST,$y)
1860     */
1861     } else if (op->opcode == ZEND_ADD_CHAR &&
1862                op->op1.op_type == IS_CONST) {
1863       size_t len;
1864       op->opcode = ZEND_QM_ASSIGN;
1865       op->op1.op_type = IS_CONST;
1866       op->op2.op_type = IS_UNUSED;
1867       convert_to_string(&op->op1.u.constant);
1868       len = op->op1.u.constant.value.str.len + 1;
1869       STR_REALLOC(op->op1.u.constant.value.str.val,len+1);
1870       op->op1.u.constant.value.str.val[len-1] = (char) op->op2.u.constant.value.lval;
1871       op->op1.u.constant.value.str.val[len] = 0;
1872       op->op1.u.constant.value.str.len = len;
1873     /* ADD_STRING(CONST,CONST,$y) => QM_ASSIGN(CONST,$y)
1874     */
1875     } else if (op->opcode == ZEND_ADD_STRING &&
1876                op->op1.op_type == IS_CONST) {
1877       size_t len;
1878       op->opcode = ZEND_QM_ASSIGN;
1879       op->op1.op_type = IS_CONST;
1880       op->op2.op_type = IS_UNUSED;
1881       convert_to_string(&op->op1.u.constant);
1882       convert_to_string(&op->op2.u.constant);
1883       len = op->op1.u.constant.value.str.len + op->op2.u.constant.value.str.len;
1884       STR_REALLOC(op->op1.u.constant.value.str.val,len+1);
1885       memcpy(op->op1.u.constant.value.str.val+op->op1.u.constant.value.str.len,
1886              op->op2.u.constant.value.str.val, op->op2.u.constant.value.str.len);
1887       op->op1.u.constant.value.str.val[len] = 0;
1888       op->op1.u.constant.value.str.len = len;
1889       STR_FREE(op->op2.u.constant.value.str.val);
1890     /* ADD_VAR(CONST,VAR,$y) => CONCAT(CONST,$y)
1891     */
1892     } else if (op->opcode == ZEND_ADD_VAR &&
1893                op->op1.op_type == IS_CONST) {
1894       op->opcode = ZEND_CONCAT;
1895     /* CONCAT('',$x,$y) + ADD_CHAR($y,CHAR,$z) => CONCAT($x, CONST, $z)
1896     */
1897     } else if (op->opcode == ZEND_ADD_CHAR &&
1898                op->op1.op_type == IS_TMP_VAR &&
1899                IS_DEFINED(op->op1) &&
1900                DEFINED_OP(op->op1)->opcode == ZEND_CONCAT &&
1901                DEFINED_OP(op->op1)->op1.op_type == IS_CONST &&
1902                DEFINED_OP(op->op1)->op1.u.constant.type == IS_STRING &&
1903                DEFINED_OP(op->op1)->op1.u.constant.value.str.len == 0) {
1904       char ch = (char) op->op2.u.constant.value.lval;
1905       zend_op *x = DEFINED_OP(op->op1);
1906       SET_UNDEFINED(op->op1);
1907       memcpy(&op->op1, &x->op2, sizeof(op->op2));
1908       op->opcode = ZEND_CONCAT;
1909       op->op2.u.constant.type = IS_STRING;
1910       op->op2.u.constant.value.str.val = emalloc(2);
1911       op->op2.u.constant.value.str.val[0] = ch;
1912       op->op2.u.constant.value.str.val[1] = '\000';
1913       op->op2.u.constant.value.str.len = 1;
1914       STR_FREE(x->op1.u.constant.value.str.val);
1915       SET_TO_NOP(x);
1916     /*
1917        CONCAT('',$x,$y) + ADD_STRING($y,$v,$z) => CONCAT($x, $v, $z)
1918        CONCAT('',$x,$y) + CONCAT($y,$v,$z)     => CONCAT($x, $v, $z)
1919        CONCAT('',$x,$y) + ADD_VAR($y,$v,$z)    => CONCAT($x, $v, $z)
1920     */
1921     } else if ((op->opcode == ZEND_ADD_STRING ||
1922                 op->opcode == ZEND_CONCAT ||
1923                 op->opcode == ZEND_ADD_VAR) &&
1924                op->op1.op_type == IS_TMP_VAR &&
1925                IS_DEFINED(op->op1) &&
1926                DEFINED_OP(op->op1)->opcode == ZEND_CONCAT &&
1927                DEFINED_OP(op->op1)->op1.op_type == IS_CONST &&
1928                DEFINED_OP(op->op1)->op1.u.constant.type == IS_STRING &&
1929                DEFINED_OP(op->op1)->op1.u.constant.value.str.len == 0) {
1930       zend_op *x = DEFINED_OP(op->op1);
1931       SET_UNDEFINED(op->op1);
1932       op->opcode = ZEND_CONCAT;
1933       memcpy(&op->op1, &x->op2, sizeof(op->op2));
1934       STR_FREE(x->op1.u.constant.value.str.val);
1935       SET_TO_NOP(x);
1936     /* ADD_CHAR($x,CONST,$y) + ADD_CHAR($y,CHAR,$z) => ADD_STRING($x, CONST, $z)
1937     */
1938     } else if (op->opcode == ZEND_ADD_CHAR &&
1939                op->op1.op_type == IS_TMP_VAR &&
1940                IS_DEFINED(op->op1) &&
1941                DEFINED_OP(op->op1)->opcode == ZEND_ADD_CHAR) {
1942       char ch1 = (char) DEFINED_OP(op->op1)->op2.u.constant.value.lval;
1943       char ch2 = (char) op->op2.u.constant.value.lval;
1944       DEFINED_OP(op->op1)->op2.u.constant.type = IS_STRING;
1945       DEFINED_OP(op->op1)->op2.u.constant.value.str.val = emalloc(3);
1946       DEFINED_OP(op->op1)->op2.u.constant.value.str.val[0] = ch1;
1947       DEFINED_OP(op->op1)->op2.u.constant.value.str.val[1] = ch2;
1948       DEFINED_OP(op->op1)->op2.u.constant.value.str.val[2] = '\000';
1949       DEFINED_OP(op->op1)->op2.u.constant.value.str.len = 2;
1950       memcpy(&DEFINED_OP(op->op1)->result, &op->result, sizeof(op->result));
1951       DEFINED_OP(op->op1)->opcode = ZEND_ADD_STRING;
1952       SET_DEFINED(DEFINED_OP(op->op1));
1953       SET_TO_NOP(op);
1954     /* CONCAT($x,CONST,$y) + ADD_CHAR($y,CONST,$z) => CONCAT($x, CONST, $z)
1955        ADD_STRING($x,CONST,$y) + ADD_CHAR($y,CONST,$z) => ADD_STRING($x, CONST, $z)
1956     */
1957     } else if (op->opcode == ZEND_ADD_CHAR &&
1958                op->op1.op_type == IS_TMP_VAR &&
1959                IS_DEFINED(op->op1) &&
1960                (DEFINED_OP(op->op1)->opcode == ZEND_CONCAT ||
1961                 DEFINED_OP(op->op1)->opcode == ZEND_ADD_STRING) &&
1962                DEFINED_OP(op->op1)->op2.op_type == IS_CONST) {
1963       size_t len;
1964       convert_to_string(&DEFINED_OP(op->op1)->op2.u.constant);
1965       len = DEFINED_OP(op->op1)->op2.u.constant.value.str.len + 1;
1966       STR_REALLOC(DEFINED_OP(op->op1)->op2.u.constant.value.str.val,len+1);
1967       DEFINED_OP(op->op1)->op2.u.constant.value.str.val[len-1] = (char) op->op2.u.constant.value.lval;
1968       DEFINED_OP(op->op1)->op2.u.constant.value.str.val[len] = 0;
1969       DEFINED_OP(op->op1)->op2.u.constant.value.str.len = len;
1970       memcpy(&DEFINED_OP(op->op1)->result, &op->result, sizeof(op->result));
1971       if (DEFINED_OP(op->op1)->op1.op_type == DEFINED_OP(op->op1)->result.op_type &&
1972           DEFINED_OP(op->op1)->op1.u.var == DEFINED_OP(op->op1)->result.u.var) {
1973         DEFINED_OP(op->op1)->opcode = ZEND_ADD_STRING;
1974       }
1975       SET_DEFINED(DEFINED_OP(op->op1));
1976       SET_TO_NOP(op);
1977     /* ADD_CHAR($x,CONST,$y) + ADD_STRING($y,CONST,$z) => ADD_STRING($x, CONST, $z)
1978        ADD_CHAR($x,CONST,$y) + CONCAT($y,CONST,$z) => CONCAT($x, CONST, $z)
1979     */
1980     } else if ((op->opcode == ZEND_ADD_STRING ||
1981                 op->opcode == ZEND_CONCAT) &&
1982                op->op2.op_type == IS_CONST &&
1983                op->op1.op_type == IS_TMP_VAR &&
1984                IS_DEFINED(op->op1) &&
1985                DEFINED_OP(op->op1)->opcode == ZEND_ADD_CHAR) {
1986       char ch = (char) DEFINED_OP(op->op1)->op2.u.constant.value.lval;
1987       size_t len;
1988       convert_to_string(&op->op2.u.constant);
1989       len = op->op2.u.constant.value.str.len + 1;
1990       DEFINED_OP(op->op1)->op2.u.constant.type = IS_STRING;
1991       DEFINED_OP(op->op1)->op2.u.constant.value.str.val = emalloc(len+1);
1992       DEFINED_OP(op->op1)->op2.u.constant.value.str.val[0] = ch;
1993       memcpy(DEFINED_OP(op->op1)->op2.u.constant.value.str.val+1,
1994              op->op2.u.constant.value.str.val, op->op2.u.constant.value.str.len);
1995       DEFINED_OP(op->op1)->op2.u.constant.value.str.val[len] = 0;
1996       DEFINED_OP(op->op1)->op2.u.constant.value.str.len = len;
1997       STR_FREE(op->op2.u.constant.value.str.val);
1998       memcpy(&DEFINED_OP(op->op1)->result, &op->result, sizeof(op->result));
1999       DEFINED_OP(op->op1)->opcode = op->opcode;
2000       if (DEFINED_OP(op->op1)->op1.op_type == DEFINED_OP(op->op1)->result.op_type &&
2001           DEFINED_OP(op->op1)->op1.u.var == DEFINED_OP(op->op1)->result.u.var) {
2002         DEFINED_OP(op->op1)->opcode = ZEND_ADD_STRING;
2003       }
2004       SET_DEFINED(DEFINED_OP(op->op1));
2005       SET_TO_NOP(op);
2006     /* ADD_STRING($x,CONST,$y) + ADD_STRING($y,CONST,$z) => ADD_STRING($x, CONST, $z)
2007        ADD_STRING($x,CONST,$y) + CONCAT($y,CONST,$z) => CONCAT($x, CONST, $z)
2008        CONCAT($x,CONST,$y) + ADD_STRING($y,CONST,$z) => CONCAT($x, CONST, $z)
2009        CONCAT($x,CONST,$y) + CONCAT($y,CONST,$z) => CONCAT($x, CONST, $z)
2010     */
2011     } else if ((op->opcode == ZEND_ADD_STRING ||
2012                 op->opcode == ZEND_CONCAT) &&
2013                op->op2.op_type == IS_CONST &&
2014                op->op1.op_type == IS_TMP_VAR &&
2015                IS_DEFINED(op->op1) &&
2016                (DEFINED_OP(op->op1)->opcode == ZEND_CONCAT ||
2017                 DEFINED_OP(op->op1)->opcode == ZEND_ADD_STRING) &&
2018                DEFINED_OP(op->op1)->op2.op_type == IS_CONST) {
2019       size_t len;
2020       convert_to_string(&DEFINED_OP(op->op1)->op2.u.constant);
2021       convert_to_string(&op->op2.u.constant);
2022       len = DEFINED_OP(op->op1)->op2.u.constant.value.str.len + op->op2.u.constant.value.str.len;
2023       STR_REALLOC(DEFINED_OP(op->op1)->op2.u.constant.value.str.val,len+1);
2024       memcpy(DEFINED_OP(op->op1)->op2.u.constant.value.str.val+DEFINED_OP(op->op1)->op2.u.constant.value.str.len,
2025              op->op2.u.constant.value.str.val, op->op2.u.constant.value.str.len);
2026       DEFINED_OP(op->op1)->op2.u.constant.value.str.val[len] = 0;
2027       DEFINED_OP(op->op1)->op2.u.constant.value.str.len = len;
2028       STR_FREE(op->op2.u.constant.value.str.val);
2029       memcpy(&DEFINED_OP(op->op1)->result, &op->result, sizeof(op->result));
2030       if (op->opcode == ZEND_CONCAT) {
2031         DEFINED_OP(op->op1)->opcode = ZEND_CONCAT;
2032       }
2033       if (DEFINED_OP(op->op1)->op1.op_type == DEFINED_OP(op->op1)->result.op_type &&
2034           DEFINED_OP(op->op1)->op1.u.var == DEFINED_OP(op->op1)->result.u.var) {
2035         DEFINED_OP(op->op1)->opcode = ZEND_ADD_STRING;
2036       }
2037       SET_DEFINED(DEFINED_OP(op->op1));
2038       SET_TO_NOP(op);
2039 #ifndef ZEND_ENGINE_2_3
2040     /* TODO: Doesn't work with PHP-5.3. Needs more research */
2041
2042     /* FETCH_X      local("GLOBALS"),$x => FETCH_X global($y),$z
2043        FETCH_DIM_X  $x,$y,$z               NOP
2044     */
2045     } else if (
2046                ((op->opcode == ZEND_FETCH_DIM_R &&
2047                 op->op1.op_type == IS_VAR &&
2048 /*???               op->extended_value == ZEND_FETCH_STANDARD &&*/
2049                 IS_DEFINED(op->op1) &&
2050                 DEFINED_OP(op->op1)->opcode == ZEND_FETCH_R) ||
2051                (op->opcode == ZEND_FETCH_DIM_W &&
2052                 op->op1.op_type == IS_VAR &&
2053                 IS_DEFINED(op->op1) &&
2054                 DEFINED_OP(op->op1)->opcode == ZEND_FETCH_W) ||
2055                (op->opcode == ZEND_FETCH_DIM_RW &&
2056                 op->op1.op_type == IS_VAR &&
2057                 IS_DEFINED(op->op1) &&
2058                 DEFINED_OP(op->op1)->opcode == ZEND_FETCH_RW) ||
2059                (op->opcode == ZEND_FETCH_DIM_IS &&
2060                 op->op1.op_type == IS_VAR &&
2061                 IS_DEFINED(op->op1) &&
2062                 DEFINED_OP(op->op1)->opcode == ZEND_FETCH_IS) ||
2063                (op->opcode == ZEND_FETCH_DIM_FUNC_ARG &&
2064                 op->op1.op_type == IS_VAR &&
2065                 IS_DEFINED(op->op1) &&
2066                 DEFINED_OP(op->op1)->opcode == ZEND_FETCH_FUNC_ARG) ||
2067                (op->opcode == ZEND_FETCH_DIM_UNSET &&
2068                 op->op1.op_type == IS_VAR &&
2069                 IS_DEFINED(op->op1) &&
2070                 DEFINED_OP(op->op1)->opcode == ZEND_FETCH_UNSET)) &&
2071                 FETCH_TYPE(DEFINED_OP(op->op1)) == ZEND_FETCH_GLOBAL &&
2072                 DEFINED_OP(op->op1)->op1.op_type == IS_CONST &&
2073                 DEFINED_OP(op->op1)->op1.u.constant.type == IS_STRING &&
2074                 DEFINED_OP(op->op1)->op1.u.constant.value.str.len == (sizeof("GLOBALS")-1) &&
2075                 memcmp(DEFINED_OP(op->op1)->op1.u.constant.value.str.val, "GLOBALS", sizeof("GLOBALS")-1) == 0) {
2076       zend_op *x = op+1;
2077       if (x->opcode != op->opcode) {
2078         x = DEFINED_OP(op->op1);
2079         SET_UNDEFINED(op->op1);
2080         STR_FREE(x->op1.u.constant.value.str.val);
2081         FETCH_TYPE(x) = ZEND_FETCH_GLOBAL;
2082         memcpy(&x->op1,&op->op2,sizeof(znode));
2083         memcpy(&x->result,&op->result,sizeof(znode));
2084         SET_DEFINED(x);
2085         SET_TO_NOP(op);
2086       }
2087 #endif
2088     /* FETCH_IS               local("GLOBALS"),$x    ISSET_ISEMPTY_VAR $y(global),res
2089        ISSET_ISEMPTY_DIM_OBJ  $x,$y,$res          => NOP
2090     */
2091     } else if (op->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ &&
2092                op->op1.op_type == IS_VAR &&
2093               IS_DEFINED(op->op1) &&
2094               DEFINED_OP(op->op1)->opcode == ZEND_FETCH_IS &&
2095               FETCH_TYPE(DEFINED_OP(op->op1)) == ZEND_FETCH_GLOBAL &&
2096               DEFINED_OP(op->op1)->op1.op_type == IS_CONST &&
2097               DEFINED_OP(op->op1)->op1.u.constant.type == IS_STRING &&
2098               DEFINED_OP(op->op1)->op1.u.constant.value.str.len == (sizeof("GLOBALS")-1) &&
2099               memcmp(DEFINED_OP(op->op1)->op1.u.constant.value.str.val, "GLOBALS", sizeof("GLOBALS")-1) == 0) {
2100       zend_op* x = DEFINED_OP(op->op1);
2101       STR_FREE(x->op1.u.constant.value.str.val);
2102       x->opcode = ZEND_ISSET_ISEMPTY_VAR;
2103       x->extended_value = op->extended_value;
2104       FETCH_TYPE(x) = ZEND_FETCH_GLOBAL;
2105       memcpy(&x->op1,&op->op2,sizeof(znode));
2106       memcpy(&x->result,&op->result,sizeof(znode));
2107       SET_DEFINED(x);
2108       SET_TO_NOP(op);
2109     } else if (op->opcode == ZEND_FREE &&
2110                op->op1.op_type == IS_TMP_VAR &&
2111                IS_DEFINED(op->op1)) {
2112       /* POST_INC + FREE => PRE_INC */
2113       if (DEFINED_OP(op->op1)->opcode == ZEND_POST_INC) {
2114         DEFINED_OP(op->op1)->opcode = ZEND_PRE_INC;
2115         DEFINED_OP(op->op1)->result.op_type = IS_VAR;
2116         DEFINED_OP(op->op1)->result.u.EA.type |= EXT_TYPE_UNUSED;
2117         SET_UNDEFINED(op->op1);
2118         SET_TO_NOP(op);
2119       /* POST_DEC + FREE => PRE_DEC */
2120       } else if (DEFINED_OP(op->op1)->opcode == ZEND_POST_DEC) {
2121         DEFINED_OP(op->op1)->opcode = ZEND_PRE_DEC;
2122         DEFINED_OP(op->op1)->result.op_type = IS_VAR;
2123         DEFINED_OP(op->op1)->result.u.EA.type |= EXT_TYPE_UNUSED;
2124         SET_UNDEFINED(op->op1);
2125         SET_TO_NOP(op);
2126       /* PRINT + FREE => ECHO */
2127       } else if (DEFINED_OP(op->op1)->opcode == ZEND_PRINT) {
2128         DEFINED_OP(op->op1)->opcode = ZEND_ECHO;
2129         DEFINED_OP(op->op1)->result.op_type = IS_UNUSED;
2130         SET_UNDEFINED(op->op1);
2131         SET_TO_NOP(op);
2132       /* BOOL + FREE => NOP + NOP */
2133       } else if (DEFINED_OP(op->op1)->opcode == ZEND_BOOL) {
2134         SET_TO_NOP(DEFINED_OP(op->op1));
2135         SET_UNDEFINED(op->op1);
2136         SET_TO_NOP(op);
2137       }
2138     /* CMP + BOOL     => CMP + NOP */
2139     } else if (op->opcode == ZEND_BOOL &&
2140                op->op1.op_type == IS_TMP_VAR &&
2141                (!global[VAR_NUM(op->op1.u.var)] ||
2142                 (op->result.op_type == IS_TMP_VAR &&
2143                  op->op1.u.var == op->result.u.var)) &&
2144                IS_DEFINED(op->op1) &&
2145                (DEFINED_OP(op->op1)->opcode == ZEND_IS_IDENTICAL ||
2146                 DEFINED_OP(op->op1)->opcode == ZEND_IS_NOT_IDENTICAL ||
2147                 DEFINED_OP(op->op1)->opcode == ZEND_IS_EQUAL ||
2148                 DEFINED_OP(op->op1)->opcode == ZEND_IS_NOT_EQUAL ||
2149                 DEFINED_OP(op->op1)->opcode == ZEND_IS_SMALLER ||
2150                 DEFINED_OP(op->op1)->opcode == ZEND_IS_SMALLER_OR_EQUAL)) {
2151       memcpy(&DEFINED_OP(op->op1)->result, &op->result, sizeof(op->result));
2152       SET_DEFINED(DEFINED_OP(op->op1));
2153       SET_TO_NOP(op);
2154     /* BOOL + BOOL     => NOP + BOOL
2155        BOOL + BOOL_NOT => NOP + BOOL_NOT
2156        BOOL + JMP...   => NOP + JMP...
2157     */
2158     } else if ((op->opcode == ZEND_BOOL ||
2159                 op->opcode == ZEND_BOOL_NOT ||
2160                 op->opcode == ZEND_JMPZ||
2161                 op->opcode == ZEND_JMPNZ ||
2162                 op->opcode == ZEND_JMPZNZ ||
2163                 op->opcode == ZEND_JMPZ_EX ||
2164                 op->opcode == ZEND_JMPNZ_EX) &&
2165                 op->op1.op_type == IS_TMP_VAR &&
2166                 (!global[VAR_NUM(op->op1.u.var)] ||
2167                  (op->result.op_type == IS_TMP_VAR &&
2168                   op->op1.u.var == op->result.u.var)) &&
2169                 IS_DEFINED(op->op1) &&
2170                 DEFINED_OP(op->op1)->opcode == ZEND_BOOL) {
2171       zend_op *x = DEFINED_OP(op->op1);
2172       SET_UNDEFINED(op->op1);
2173       memcpy(&op->op1, &x->op1, sizeof(op->op1));
2174       SET_TO_NOP(x);
2175     /* BOOL_NOT + BOOL     => NOP + BOOL_NOT
2176        BOOL_NOT + BOOL_NOT => NOP + BOOL
2177        BOOL_NOT + JMP...   => NOP + JMP[n]...
2178     */
2179     } else if ((op->opcode == ZEND_BOOL ||
2180                 op->opcode == ZEND_BOOL_NOT ||
2181                 op->opcode == ZEND_JMPZ||
2182                 op->opcode == ZEND_JMPNZ) &&
2183                 op->op1.op_type == IS_TMP_VAR &&
2184                 (!global[VAR_NUM(op->op1.u.var)] ||
2185                  (op->result.op_type == IS_TMP_VAR &&
2186                   op->op1.u.var == op->result.u.var)) &&
2187                 IS_DEFINED(op->op1) &&
2188                 DEFINED_OP(op->op1)->opcode == ZEND_BOOL_NOT) {
2189       zend_op *x = DEFINED_OP(op->op1);
2190       switch (op->opcode) {
2191         case ZEND_BOOL:     op->opcode = ZEND_BOOL_NOT; break;
2192         case ZEND_BOOL_NOT: op->opcode = ZEND_BOOL;     break;
2193         case ZEND_JMPZ:     op->opcode = ZEND_JMPNZ;    break;
2194         case ZEND_JMPNZ:    op->opcode = ZEND_JMPZ;     break;
2195       }
2196       SET_UNDEFINED(op->op1);
2197       memcpy(&op->op1, &x->op1, sizeof(op->op1));
2198       SET_TO_NOP(x);
2199     /* function_exists(STR) or is_callable(STR) */
2200     } else if ((op->opcode == ZEND_BOOL ||
2201                 op->opcode == ZEND_BOOL_NOT ||
2202                 op->opcode == ZEND_JMPZ||
2203                 op->opcode == ZEND_JMPNZ ||
2204                 op->opcode == ZEND_JMPZNZ ||
2205                 op->opcode == ZEND_JMPZ_EX ||
2206                 op->opcode == ZEND_JMPNZ_EX) &&
2207                 op->op1.op_type == IS_VAR &&
2208                 !global[VAR_NUM(op->op1.u.var)] &&
2209                 IS_DEFINED(op->op1) &&
2210                 DEFINED_OP(op->op1)->opcode == ZEND_DO_FCALL &&
2211                 DEFINED_OP(op->op1)->extended_value == 1 &&
2212                 DEFINED_OP(op->op1)->op1.op_type == IS_CONST &&
2213                 DEFINED_OP(op->op1)->op1.u.constant.type == IS_STRING) {
2214       zend_op* call = DEFINED_OP(op->op1);
2215       zend_op* send = call-1;
2216       if (send->opcode == ZEND_SEND_VAL &&
2217           send->extended_value == ZEND_DO_FCALL &&
2218           send->op1.op_type == IS_CONST &&
2219           send->op1.u.constant.type == IS_STRING &&
2220           (strcmp(call->op1.u.constant.value.str.val,"function_exists") == 0 ||
2221            strcmp(call->op1.u.constant.value.str.val,"is_callable") == 0)) {
2222         if (opt_function_exists(send->op1.u.constant.value.str.val, send->op1.u.constant.value.str.len  TSRMLS_CC)) {
2223           SET_UNDEFINED(op->op1);
2224           zval_dtor(&send->op1.u.constant);
2225           SET_TO_NOP(send);
2226           zval_dtor(&call->op1.u.constant);
2227           SET_TO_NOP(call);
2228           op->op1.op_type = IS_CONST;
2229           op->op1.u.constant.type = IS_BOOL;
2230           op->op1.u.constant.value.lval = 1;
2231         }
2232       } else if (send->opcode == ZEND_SEND_VAL &&
2233           send->extended_value == ZEND_DO_FCALL &&
2234           send->op1.op_type == IS_CONST &&
2235           send->op1.u.constant.type == IS_STRING &&
2236           strcmp(call->op1.u.constant.value.str.val,"extension_loaded") == 0) {
2237         if (opt_extension_loaded(send->op1.u.constant.value.str.val, send->op1.u.constant.value.str.len  TSRMLS_CC)) {
2238           SET_UNDEFINED(op->op1);
2239           zval_dtor(&send->op1.u.constant);
2240           SET_TO_NOP(send);
2241           zval_dtor(&call->op1.u.constant);
2242           SET_TO_NOP(call);
2243           op->op1.op_type = IS_CONST;
2244           op->op1.u.constant.type = IS_BOOL;
2245           op->op1.u.constant.value.lval = 1;
2246         }
2247       } else if (send->opcode == ZEND_SEND_VAL &&
2248           send->extended_value == ZEND_DO_FCALL &&
2249           send->op1.op_type == IS_CONST &&
2250           send->op1.u.constant.type == IS_STRING &&
2251           strcmp(call->op1.u.constant.value.str.val,"defined") == 0) {
2252         zend_constant *c = NULL;
2253         if (opt_get_constant(send->op1.u.constant.value.str.val, send->op1.u.constant.value.str.len, &c TSRMLS_CC) && c != NULL && ((c->flags & CONST_PERSISTENT) != 0)) {
2254           SET_UNDEFINED(op->op1);
2255           zval_dtor(&send->op1.u.constant);
2256           SET_TO_NOP(send);
2257           zval_dtor(&call->op1.u.constant);
2258           SET_TO_NOP(call);
2259           op->op1.op_type = IS_CONST;
2260           op->op1.u.constant.type = IS_BOOL;
2261           op->op1.u.constant.value.lval = 1;
2262         }
2263       }
2264     /* QM_ASSIGN($x,$x) => NOP */
2265     } else if (op->opcode == ZEND_QM_ASSIGN &&
2266                op->op1.op_type == IS_TMP_VAR &&
2267                op->result.op_type == IS_TMP_VAR &&
2268                op->op1.u.var == op->result.u.var) {
2269       SET_TO_NOP(op);
2270     /* ?(,,$tmp_x) +QM_ASSIGN($tmp_x,$tmp_y) => ?(,,$tmp_y) + NOP */
2271     } else if (op->opcode == ZEND_QM_ASSIGN &&
2272                op->op1.op_type == IS_TMP_VAR &&
2273                !global[VAR_NUM(op->op1.u.var)] &&
2274                op->op1.u.var != op->result.u.var &&
2275                IS_DEFINED(op->op1)) {
2276       zend_op *x = DEFINED_OP(op->op1);
2277       if (x->opcode != ZEND_ADD_ARRAY_ELEMENT &&
2278           x->opcode != ZEND_ADD_STRING &&
2279           x->opcode != ZEND_ADD_CHAR &&
2280           x->opcode != ZEND_ADD_VAR) {
2281         SET_UNDEFINED(op->op1);
2282         memcpy(&x->result, &op->result, sizeof(op->result));
2283         SET_DEFINED(x);
2284         SET_TO_NOP(op);
2285       }
2286     /* ECHO(const) + ECHO(const) => ECHO(const) */
2287     } else if (prev != NULL &&
2288                op->opcode == ZEND_ECHO &&
2289                op->op1.op_type == IS_CONST &&
2290                prev->opcode == ZEND_ECHO &&
2291                prev->op1.op_type == IS_CONST) {
2292       int len;
2293       convert_to_string(&prev->op1.u.constant);
2294       convert_to_string(&op->op1.u.constant);
2295       len = prev->op1.u.constant.value.str.len + op->op1.u.constant.value.str.len;
2296       STR_REALLOC(prev->op1.u.constant.value.str.val,len+1);
2297       memcpy(prev->op1.u.constant.value.str.val+prev->op1.u.constant.value.str.len,
2298              op->op1.u.constant.value.str.val, op->op1.u.constant.value.str.len);
2299       prev->op1.u.constant.value.str.val[len] = 0;
2300       prev->op1.u.constant.value.str.len = len;
2301       STR_FREE(op->op1.u.constant.value.str.val);
2302       SET_TO_NOP(op);
2303     /* END_SILENCE + BEGIN_SILENCE => NOP + NOP */
2304     } else if (prev != NULL &&
2305                prev->opcode == ZEND_END_SILENCE &&
2306                op->opcode == ZEND_BEGIN_SILENCE) {
2307       zend_op *x = op+1;
2308       while (x < end) {
2309         if (x->opcode == ZEND_END_SILENCE &&
2310             x->op1.u.var == op->result.u.var) {
2311           x->op1.u.var = prev->op1.u.var;
2312           SET_TO_NOP(prev);
2313           SET_TO_NOP(op);
2314           break;
2315         }
2316         x++;
2317       }
2318     /* BEGIN_SILENCE + END_SILENCE => NOP + NOP */
2319     } else if (prev != NULL &&
2320                prev->opcode == ZEND_BEGIN_SILENCE &&
2321                op->opcode == ZEND_END_SILENCE &&
2322                prev->result.u.var == op->op1.u.var) {
2323       SET_TO_NOP(prev);
2324       SET_TO_NOP(op);
2325     /* SEND_VAR_NO_REF => SEND_VAR (cond) */
2326     } else if (op->opcode == ZEND_SEND_VAR_NO_REF &&
2327                (op->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) &&
2328                !(op->extended_value & ZEND_ARG_SEND_BY_REF)) {
2329       op->opcode = ZEND_SEND_VAR;
2330       op->extended_value = ZEND_DO_FCALL;
2331     /* INIT_FCALL_BY_NAME + DO_FCALL_BY_NAME => DO_FCALL $x */
2332     } else if (prev != NULL &&
2333                op->opcode == ZEND_DO_FCALL_BY_NAME &&
2334                op->extended_value == 0 &&
2335                op->op1.op_type == IS_CONST &&
2336                op->op1.u.constant.type == IS_STRING &&
2337                prev->opcode == ZEND_INIT_FCALL_BY_NAME &&
2338                prev->op1.op_type == IS_UNUSED &&
2339                prev->op2.op_type == IS_CONST &&
2340                prev->op2.u.constant.type == IS_STRING &&
2341                op->op1.u.constant.value.str.len == prev->op2.u.constant.value.str.len &&
2342                (memcmp(op->op1.u.constant.value.str.val,prev->op2.u.constant.value.str.val,op->op1.u.constant.value.str.len) == 0)) {
2343        op->opcode = ZEND_DO_FCALL;
2344        STR_FREE(prev->op2.u.constant.value.str.val);
2345        SET_TO_NOP(prev);
2346     }
2347
2348     /* $a = $a + ? => $a+= ? */
2349     if (op->opcode == ZEND_ASSIGN &&
2350         op->op1.op_type == IS_VAR &&
2351         op->op2.op_type == IS_TMP_VAR &&
2352         IS_DEFINED(op->op1) &&
2353         IS_DEFINED(op->op2)) {
2354       zend_op* l = DEFINED_OP(op->op1);
2355       zend_op* r = DEFINED_OP(op->op2);
2356       if (l->opcode == ZEND_FETCH_W &&
2357           l->op1.op_type == IS_CONST &&
2358           l->op1.u.constant.type == IS_STRING &&
2359           (r->opcode  == ZEND_ADD ||
2360            r->opcode  == ZEND_SUB ||
2361            r->opcode  == ZEND_MUL ||
2362            r->opcode  == ZEND_DIV ||
2363            r->opcode  == ZEND_MOD ||
2364            r->opcode  == ZEND_SL ||
2365            r->opcode  == ZEND_SR ||
2366            r->opcode  == ZEND_CONCAT ||
2367            r->opcode  == ZEND_BW_OR ||
2368            r->opcode  == ZEND_BW_AND ||
2369            r->opcode  == ZEND_BW_XOR) &&
2370          r->op1.op_type == IS_VAR &&
2371          IS_DEFINED(r->op1)) {
2372         zend_op* rl = DEFINED_OP(r->op1);
2373         if (rl->opcode == ZEND_FETCH_R &&
2374             rl->op1.op_type == IS_CONST &&
2375             rl->op1.u.constant.type == IS_STRING &&
2376             FETCH_TYPE(rl) == FETCH_TYPE(l) &&
2377             l->op1.u.constant.value.str.len ==
2378               rl->op1.u.constant.value.str.len &&
2379             memcmp(l->op1.u.constant.value.str.val,
2380               rl->op1.u.constant.value.str.val,
2381               l->op1.u.constant.value.str.len) == 0) {
2382           switch (r->opcode) {
2383             case ZEND_ADD:    op->opcode = ZEND_ASSIGN_ADD; break;
2384             case ZEND_SUB:    op->opcode = ZEND_ASSIGN_SUB; break;
2385             case ZEND_MUL:    op->opcode = ZEND_ASSIGN_MUL; break;
2386             case ZEND_DIV:    op->opcode = ZEND_ASSIGN_DIV; break;
2387             case ZEND_MOD:    op->opcode = ZEND_ASSIGN_MOD; break;
2388             case ZEND_SL:     op->opcode = ZEND_ASSIGN_SL;  break;
2389             case ZEND_SR:     op->opcode = ZEND_ASSIGN_SR;  break;
2390             case ZEND_CONCAT: op->opcode = ZEND_ASSIGN_CONCAT; break;
2391             case ZEND_BW_OR:  op->opcode = ZEND_ASSIGN_BW_OR;  break;
2392             case ZEND_BW_AND: op->opcode = ZEND_ASSIGN_BW_AND; break;
2393             case ZEND_BW_XOR: op->opcode = ZEND_ASSIGN_BW_XOR; break;
2394             default:
2395               break;
2396           }
2397           memcpy(&op->op2, &r->op2, sizeof(op->op2));
2398           l->opcode = ZEND_FETCH_RW;
2399           SET_TO_NOP(r);
2400           STR_FREE(rl->op1.u.constant.value.str.val);
2401           SET_TO_NOP(rl);
2402         }
2403       }
2404     }
2405
2406     if (pass == 1) {
2407       /* FETCH_W var,$x + ASSIGN $x,?,_  + FETCH_R var,$y =>
2408          FETCH_W var,$x + ASSIGN $x,?,$y */
2409       if (op->opcode == ZEND_UNSET_VAR ||
2410           op->opcode == ZEND_DO_FCALL ||
2411           op->opcode == ZEND_DO_FCALL_BY_NAME ||
2412           op->opcode == ZEND_POST_INC ||
2413           op->opcode == ZEND_POST_DEC ||
2414           op->opcode == ZEND_UNSET_DIM ||
2415           op->opcode == ZEND_UNSET_OBJ ||
2416           op->opcode == ZEND_INCLUDE_OR_EVAL ||
2417           op->opcode == ZEND_ASSIGN_DIM ||
2418           op->opcode == ZEND_ASSIGN_OBJ) {
2419         zend_hash_clean(&assigns);
2420         zend_hash_clean(&fetch_dim);
2421       } else if (op->opcode == ZEND_ASSIGN_REF ||
2422                  op->opcode == ZEND_ASSIGN ||
2423                  op->opcode == ZEND_PRE_INC ||
2424                  op->opcode == ZEND_PRE_DEC ||
2425                  op->opcode == ZEND_ASSIGN_ADD ||
2426                  op->opcode == ZEND_ASSIGN_SUB ||
2427                  op->opcode == ZEND_ASSIGN_MUL ||
2428                  op->opcode == ZEND_ASSIGN_DIV ||
2429                  op->opcode == ZEND_ASSIGN_MOD ||
2430                  op->opcode == ZEND_ASSIGN_SL ||
2431                  op->opcode == ZEND_ASSIGN_SR ||
2432                  op->opcode == ZEND_ASSIGN_CONCAT ||
2433                  op->opcode == ZEND_ASSIGN_BW_OR ||
2434                  op->opcode == ZEND_ASSIGN_BW_AND ||
2435                  op->opcode == ZEND_ASSIGN_BW_XOR) {
2436         zend_hash_clean(&assigns);
2437         zend_hash_clean(&fetch_dim);
2438         if ((op->result.u.EA.type & EXT_TYPE_UNUSED) != 0 &&
2439             op->op1.op_type == IS_VAR &&
2440             op->extended_value != ZEND_ASSIGN_DIM &&
2441             op->extended_value != ZEND_ASSIGN_OBJ &&
2442             IS_DEFINED(op->op1)) {
2443           zend_op *x = DEFINED_OP(op->op1);
2444           if ((x->opcode == ZEND_FETCH_W || x->opcode == ZEND_FETCH_RW) &&
2445               x->op1.op_type == IS_CONST && x->op1.u.constant.type == IS_STRING) {
2446             union {
2447               zend_op *v;
2448               void *ptr;
2449             } op_copy;
2450             char *s = emalloc(x->op1.u.constant.value.str.len+2);
2451             op_copy.v = op;
2452             memcpy(s,x->op1.u.constant.value.str.val,x->op1.u.constant.value.str.len);
2453             s[x->op1.u.constant.value.str.len] = (char)FETCH_TYPE(x);
2454             s[x->op1.u.constant.value.str.len+1] = '\0';
2455             zend_hash_update(&assigns, s, x->op1.u.constant.value.str.len+2, &op_copy.ptr,
2456                 sizeof(void*), NULL);
2457             efree(s);
2458           }
2459         }
2460       } else if ((op->opcode == ZEND_FETCH_R || op->opcode == ZEND_FETCH_IS) &&
2461           !global[VAR_NUM(op->result.u.var)] && op->op1.op_type == IS_CONST &&
2462           op->op1.u.constant.type == IS_STRING) {
2463         union {
2464           zend_op *v;
2465           void *ptr;
2466         } x;
2467         char *s = emalloc(op->op1.u.constant.value.str.len+2);
2468         memcpy(s,op->op1.u.constant.value.str.val,op->op1.u.constant.value.str.len);
2469         s[op->op1.u.constant.value.str.len] = (char)FETCH_TYPE(op);
2470         s[op->op1.u.constant.value.str.len+1] = '\0';
2471
2472         if (zend_hash_find(&assigns, s, op->op1.u.constant.value.str.len+2,
2473               &x.ptr) == SUCCESS) {
2474           x.v = *(zend_op**)x.v;
2475           memcpy(&x.v->result, &op->result, sizeof(op->result));
2476           x.v->result.u.EA.type = 0;
2477           SET_DEFINED(x.v);
2478           zend_hash_del(&assigns, s, op->op1.u.constant.value.str.len+2);
2479           STR_FREE(op->op1.u.constant.value.str.val);
2480           SET_TO_NOP(op);
2481         }
2482         efree(s);
2483       } else if (op->opcode == ZEND_FETCH_DIM_R &&
2484           op->extended_value != ZEND_FETCH_ADD_LOCK &&
2485           op->op1.op_type == IS_VAR &&
2486           IS_DEFINED(op->op1)) {
2487         zend_op *x = DEFINED_OP(op->op1);
2488         while ((x->opcode == ZEND_ASSIGN_REF ||
2489                 x->opcode == ZEND_ASSIGN ||
2490                 x->opcode == ZEND_PRE_INC ||
2491                 x->opcode == ZEND_PRE_DEC ||
2492                 x->opcode == ZEND_ASSIGN_ADD ||
2493                 x->opcode == ZEND_ASSIGN_SUB ||
2494                 x->opcode == ZEND_ASSIGN_MUL ||
2495                 x->opcode == ZEND_ASSIGN_DIV ||
2496                 x->opcode == ZEND_ASSIGN_MOD ||
2497                 x->opcode == ZEND_ASSIGN_SL ||
2498                 x->opcode == ZEND_ASSIGN_SR ||
2499                 x->opcode == ZEND_ASSIGN_CONCAT ||
2500                 x->opcode == ZEND_ASSIGN_BW_OR ||
2501                 x->opcode == ZEND_ASSIGN_BW_AND ||
2502                 x->opcode == ZEND_ASSIGN_BW_XOR) &&
2503                 x->op1.op_type == IS_VAR &&
2504                 IS_DEFINED(x->op1)) {
2505           x = DEFINED_OP(x->op1);
2506         }
2507         if ((x->opcode == ZEND_FETCH_R || x->opcode == ZEND_FETCH_W ||
2508               x->opcode == ZEND_FETCH_RW) && x->op1.op_type == IS_CONST &&
2509             x->op1.u.constant.type == IS_STRING) {
2510           union {
2511             zend_op *v;
2512             void *ptr;
2513           } y;
2514           union {
2515             zend_op *v;
2516             void *ptr;
2517           } op_copy;
2518           char *s = emalloc(x->op1.u.constant.value.str.len+2);
2519           op_copy.v = op;
2520           memcpy(s,x->op1.u.constant.value.str.val,x->op1.u.constant.value.str.len);
2521           s[x->op1.u.constant.value.str.len] = (char)FETCH_TYPE(x);
2522           s[x->op1.u.constant.value.str.len+1] = '\0';
2523           if (zend_hash_find(&fetch_dim, s, x->op1.u.constant.value.str.len+2,
2524                 &y.ptr) == SUCCESS) {
2525             y.v = *(zend_op**)y.v;
2526             y.v->extended_value = ZEND_FETCH_ADD_LOCK;
2527             zend_hash_update(&fetch_dim, s, x->op1.u.constant.value.str.len+2,
2528                 &op_copy.ptr, sizeof(void*), NULL);
2529             SET_UNDEFINED(x->result);
2530             STR_FREE(x->op1.u.constant.value.str.val);
2531             SET_TO_NOP(x);
2532             memcpy(&op->op1, &y.v->op1, sizeof(op->op1));
2533           } else {
2534             zend_hash_update(&fetch_dim, s, x->op1.u.constant.value.str.len+2,
2535                 &op_copy.ptr, sizeof(void*), NULL);
2536           }
2537           efree(s);
2538         }
2539       }
2540     }
2541
2542     if (op->opcode != ZEND_NOP) {
2543       prev = op;
2544     }
2545     if ((op->result.op_type == IS_VAR &&
2546         (op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT ||
2547          (op->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
2548         (op->result.op_type == IS_TMP_VAR)) {
2549       if (op->opcode == ZEND_RECV ||
2550           op->opcode == ZEND_RECV_INIT) {
2551         SET_UNDEFINED(op->result);
2552       } else {
2553         SET_DEFINED(op);
2554       }
2555     }
2556     ++op;
2557   }
2558
2559   /* NOP Removing */
2560   op = bb->start;
2561   end = op + bb->len;
2562   while (op < end) {
2563     if (op->opcode == ZEND_NOP) {
2564       zend_op *next = op+1;
2565       while (next < end && next->opcode == ZEND_NOP) next++;
2566       if (next < end) {
2567         memmove(op,next,(end-next) * sizeof(zend_op));
2568         while (next > op) {
2569           --end;
2570           SET_TO_NOP(end);
2571           --next;
2572         }
2573       } else {
2574         end -= (next-op);
2575       }
2576     } else {
2577       ++op;
2578     }
2579   }
2580   bb->len = end - bb->start;
2581   zend_hash_destroy(&fetch_dim);
2582   zend_hash_destroy(&assigns);
2583 #ifdef ZEND_ENGINE_2_3
2584   free_alloca(Ts, use_heap);
2585 #else
2586   free_alloca(Ts);
2587 #endif
2588 }
2589
2590 /*
2591  * Find All Basic Blocks in op_array and build Control Flow Graph (CFG)
2592  */
2593 static int build_cfg(zend_op_array *op_array, BB* bb)
2594 {
2595         zend_op* op = op_array->opcodes;
2596         int len = op_array->last;
2597         int line_num;
2598         BB* p;
2599         int remove_brk_cont_array = 1;
2600
2601     /* HOESH: Just to use later... */
2602         zend_uint innermost_ketchup;
2603
2604         /* HOESH: Mark try & catch blocks */
2605         if (op_array->last_try_catch > 0)
2606         {
2607                 int i;
2608                 zend_try_catch_element* tc_element = op_array->try_catch_array;
2609                 for (i=0; i<op_array->last_try_catch; i++, tc_element++)
2610                 {
2611                         bb[tc_element->try_op].start = &op_array->opcodes[tc_element->try_op];
2612                         bb[tc_element->try_op].protect_merge = 1;
2613
2614                         bb[tc_element->catch_op].start = &op_array->opcodes[tc_element->catch_op];
2615                         bb[tc_element->catch_op].protect_merge = 1;
2616                 }
2617         }
2618        
2619     /* Find Starts of Basic Blocks */
2620         bb[0].start = op;
2621         for (line_num=0; line_num < len; op++,line_num++)
2622         {
2623                 const opcode_dsc* dsc = get_opcode_dsc(op->opcode);
2624                 if (dsc != NULL)
2625                 {
2626 #ifndef ZEND_ENGINE_2_3
2627                         /* Does not work with PHP 5.3 due to namespaces */
2628                         if ((dsc->ops & OP1_MASK) == OP1_UCLASS)
2629                         {
2630                                 if (op->op1.op_type != IS_UNUSED)
2631                                 {
2632                                         op->op1.op_type = IS_VAR;
2633
2634                                 }
2635                         }
2636                         else if ((dsc->ops & OP1_MASK) == OP1_CLASS)
2637                         {
2638                                 op->op1.op_type = IS_VAR;
2639                         }
2640                         else
2641 #endif
2642                         if ((dsc->ops & OP1_MASK) == OP1_UNUSED)
2643                         {
2644                                 op->op1.op_type = IS_UNUSED;
2645                         }
2646                         if ((dsc->ops & OP2_MASK) == OP2_CLASS)
2647                         {
2648                                 op->op2.op_type = IS_VAR;
2649                         }
2650                         else if ((dsc->ops & OP2_MASK) == OP2_UNUSED)
2651                         {
2652                                 op->op2.op_type = IS_UNUSED;
2653                         }
2654                         else if ((dsc->ops & OP2_MASK) == OP2_FETCH &&
2655                                         op->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER)
2656                         {
2657                                 op->op2.op_type = IS_VAR;
2658                         }
2659                         if ((dsc->ops & RES_MASK) == RES_CLASS)
2660                         {
2661                                 op->result.op_type = IS_VAR;
2662                                 op->result.u.EA.type &= ~EXT_TYPE_UNUSED;
2663                         }
2664                         else if ((dsc->ops & RES_MASK) == RES_UNUSED)
2665                         {
2666                                 op->result.op_type = IS_UNUSED;
2667                         }
2668                 }
2669                 switch(op->opcode)
2670                 {
2671                         case ZEND_RETURN:
2672                         case ZEND_EXIT:
2673                                 bb[line_num+1].start = op+1;
2674                                 break;
2675 #ifdef ZEND_GOTO
2676                         case ZEND_GOTO:
2677 #endif
2678                         case ZEND_JMP:
2679                                 bb[op->op1.u.opline_num].start = &op_array->opcodes[op->op1.u.opline_num];
2680                                 bb[line_num+1].start = op+1;
2681                                 break;
2682                         case ZEND_JMPZNZ:
2683                                 bb[op->extended_value].start = &op_array->opcodes[op->extended_value];
2684                                 bb[op->op2.u.opline_num].start = &op_array->opcodes[op->op2.u.opline_num];
2685                                 bb[line_num+1].start = op+1;
2686                                 break;
2687                         case ZEND_JMPZ:
2688                         case ZEND_JMPNZ:
2689                         case ZEND_JMPZ_EX:
2690                         case ZEND_JMPNZ_EX:
2691 #ifdef ZEND_JMP_SET
2692                         case ZEND_JMP_SET:
2693 #endif
2694                         case ZEND_NEW:
2695                         case ZEND_FE_RESET:
2696                         case ZEND_FE_FETCH:
2697                                 bb[line_num+1].start = op+1;
2698                                 bb[op->op2.u.opline_num].start = &op_array->opcodes[op->op2.u.opline_num];
2699                                 break;
2700                         case ZEND_BRK:
2701                                 /* Replace BRK by JMP */
2702                                 if (op->op1.u.opline_num == -1)
2703                                 {
2704                                 }
2705                                 else if (op->op2.op_type == IS_CONST &&
2706                                                 op->op2.u.constant.type == IS_LONG)
2707                                 {
2708                                         int level  = op->op2.u.constant.value.lval;
2709                                         zend_uint offset = op->op1.u.opline_num;
2710                                         zend_brk_cont_element *jmp_to;
2711                                         do
2712                                         {
2713                                                 if (offset < 0 || offset >= op_array->last_brk_cont)
2714                                                 {
2715                                                         goto brk_failed;
2716                                                 }
2717                                                 jmp_to = &op_array->brk_cont_array[offset];
2718                                                 if (level>1 &&
2719                                                         (op_array->opcodes[jmp_to->brk].opcode == ZEND_SWITCH_FREE ||
2720                                                         op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE))
2721                                                 {
2722                                                         goto brk_failed;
2723                                                 }
2724                                                 offset = jmp_to->parent;
2725                                         }
2726                                         while (--level > 0);
2727                                         op->opcode = ZEND_JMP;
2728                                         op->op1.u.opline_num = jmp_to->brk;
2729                                         op->op2.op_type = IS_UNUSED;
2730                                         op->extended_value = ZEND_BRK; /* Mark the opcode as former ZEND_BRK */
2731                                         bb[op->op1.u.opline_num].start = &op_array->opcodes[jmp_to->brk];
2732                                 }
2733                                 else
2734                                 {
2735 brk_failed:
2736                                   remove_brk_cont_array = 0;
2737                                 }
2738                                 bb[line_num+1].start = op+1;
2739                                 break;
2740                         case ZEND_CONT:
2741                                 /* Replace CONT by JMP */
2742                                 if (op->op1.u.opline_num == -1)
2743                                 {
2744                                 }
2745                                 else if (op->op2.op_type == IS_CONST &&
2746                                                 op->op2.u.constant.type == IS_LONG)
2747                                 {
2748                                 int level  = op->op2.u.constant.value.lval;
2749                                 zend_uint offset = op->op1.u.opline_num;
2750                                 zend_brk_cont_element *jmp_to;
2751                                 do
2752                                 {
2753                                         if (offset < 0 || offset >= op_array->last_brk_cont)
2754                                         {
2755                                                 goto cont_failed;
2756                                         }
2757                                         jmp_to = &op_array->brk_cont_array[offset];
2758                                         if (level>1 &&
2759                                                 (op_array->opcodes[jmp_to->brk].opcode == ZEND_SWITCH_FREE ||
2760                                                 op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE))
2761                                         {
2762                                                 goto cont_failed;
2763                                         }
2764                                         offset = jmp_to->parent;
2765                                 }
2766                                 while (--level > 0);
2767                                 op->opcode = ZEND_JMP;
2768                                 op->op1.u.opline_num = jmp_to->cont;
2769                                 op->op2.op_type = IS_UNUSED;
2770                                 op->extended_value = ZEND_CONT; /* Mark the opcode as former ZEND_CONT */
2771                                 bb[op->op1.u.opline_num].start = &op_array->opcodes[jmp_to->cont];
2772                                 }
2773                                 else
2774                                 {
2775 cont_failed:
2776                                         remove_brk_cont_array = 0;
2777                                 }
2778                                 bb[line_num+1].start = op+1;
2779                                 break;
2780                         case ZEND_CATCH:
2781                                 bb[op->extended_value].start = &op_array->opcodes[op->extended_value];
2782                                 bb[line_num+1].start = op+1;
2783                                 break;
2784                         case ZEND_THROW:
2785                                 if (op->op2.u.opline_num != -1)
2786                                 {
2787                                         bb[op->op2.u.opline_num].start = &op_array->opcodes[op->op2.u.opline_num];
2788                                 }
2789                                 bb[line_num+1].start = op+1;
2790                                 break;
2791                         case ZEND_DO_FCALL:
2792                         case ZEND_DO_FCALL_BY_NAME:
2793                                 bb[line_num+1].start = op+1;
2794                                 break;
2795                         case ZEND_UNSET_VAR:
2796                         case ZEND_UNSET_DIM:
2797                                 op->result.op_type = IS_UNUSED;
2798                                 break;
2799                         case ZEND_UNSET_OBJ:
2800                                 op->result.op_type = IS_UNUSED;
2801                                 break;
2802                         default:
2803                                 break;
2804                 }
2805         }
2806
2807         /* Find Lengths of Basic Blocks and build CFG */
2808         p = bb;
2809         for (line_num=1; line_num < len; line_num++)
2810         {
2811                 /* Calculate innermost CATCH op */
2812                 innermost_ketchup = 0;
2813                 if (op_array->last_try_catch > 0)
2814                 {
2815                         int i;
2816                         zend_try_catch_element* tc_element = op_array->try_catch_array;
2817                         for (i=0; i<op_array->last_try_catch; i++, tc_element++)
2818                         {
2819                                 // silence compile warnings. Line_num can't be negative here so casting is safe.
2820                                 if (tc_element->try_op <= (zend_uint)line_num-1 &&
2821                                         (zend_uint)line_num-1 < tc_element->catch_op &&
2822                                                 (innermost_ketchup == 0 ||
2823                                                 innermost_ketchup > tc_element->catch_op)
2824                                         )
2825                                 {
2826                                         innermost_ketchup = tc_element->catch_op;
2827                                 }
2828                         }
2829                 }
2830                 if (bb[line_num].start != NULL)
2831                 {
2832                         p->len  = bb[line_num].start - p->start;
2833                         p->next = &bb[line_num];
2834                         op = &p->start[p->len-1];
2835                         switch (op->opcode)
2836                         {
2837                                 case ZEND_JMP:
2838                                     p->jmp_1 = &bb[op->op1.u.opline_num];
2839 if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 2 && PHP_RELEASE_VERSION >= 1) || PHP_MAJOR_VERSION >= 6
2840                                         /* php >= 5.2.1 introduces a ZEND_JMP before a ZEND_FETCH_CLASS and ZEND_CATCH
2841                                            this leaves those blocks intact */
2842                                         if ((op+1)->opcode == ZEND_FETCH_CLASS && (op+2)->opcode == ZEND_CATCH) { /* fix for #242 */
2843                                                 p->follow = &bb[line_num];
2844                                         }
2845 endif
2846                                         break;
2847                                 case ZEND_JMPZNZ:
2848                                         p->jmp_2 = &bb[op->op2.u.opline_num];
2849                                         p->jmp_ext = &bb[op->extended_value];
2850                                         break;
2851                                 case ZEND_JMPZ:
2852                                 case ZEND_JMPNZ:
2853                                 case ZEND_JMPZ_EX:
2854                                 case ZEND_JMPNZ_EX:
2855                                 case ZEND_NEW:
2856                                 case ZEND_FE_RESET:
2857                                 case ZEND_FE_FETCH:
2858 #ifdef ZEND_JMP_SET
2859                                 case ZEND_JMP_SET:
2860 #endif
2861                                         p->jmp_2 = &bb[op->op2.u.opline_num];
2862                                         p->follow = &bb[line_num];
2863                                         break;
2864 #ifdef ZEND_GOTO
2865                                 case ZEND_GOTO:
2866                                         p->jmp_1 = &bb[op->op1.u.opline_num];
2867                                         p->follow = &bb[line_num];
2868                                         break;
2869 #endif
2870                                 case ZEND_RETURN:
2871                                 case ZEND_EXIT:
2872                                 case ZEND_BRK:
2873                                 case ZEND_CONT:
2874                                         /* HOESH: The control might flow to the innermost CATCH
2875                                          * op if an exception thrown earlier. We can follow to CATCH
2876                                          * to protect it against unnecessary K.O. In that case,
2877                                          * the last RETURN will hold HANDLE_EXCEPTION.
2878                                          * If no CATCH op toward, then glue it to the last opcode,
2879                                          * that is HANDLE_EXCEPTION.
2880                                          */
2881                                         p->follow = (innermost_ketchup > 0) ? &bb[innermost_ketchup] : &bb[len-1];
2882                                         break;
2883                                 case ZEND_DO_FCALL:
2884                                 case ZEND_DO_FCALL_BY_NAME:
2885                                         p->follow = &bb[line_num];
2886                                         break;
2887                                 case ZEND_CATCH:
2888                                         p->jmp_ext = &bb[op->extended_value];
2889                                         p->follow = &bb[line_num];
2890                                         break;
2891                                 case ZEND_THROW:
2892                                         if (op->op2.u.opline_num != -1)
2893                                         {
2894                                                 p->jmp_2 = &bb[op->op2.u.opline_num];
2895                                         }
2896                                         p->follow = &bb[line_num];
2897                                         break;
2898                                 default:
2899                                         p->follow = &bb[line_num];
2900                         }
2901                         p = &bb[line_num];
2902                 }
2903         }
2904         p->len = (op_array->opcodes + op_array->last) - p->start;
2905
2906         /* Remove Unused brk_cont_array (BRK and CONT instructions replaced by JMP)
2907         TODO: cannot be removed when ZEND_GOTO is used in oparray with php 5.3+
2908         if (remove_brk_cont_array)
2909         {
2910                 if (op_array->brk_cont_array != NULL)
2911                 {
2912                         efree(op_array->brk_cont_array);
2913                         op_array->brk_cont_array = NULL;
2914                 }
2915                 op_array->last_brk_cont = 0;
2916         }*/
2917         return remove_brk_cont_array;
2918 }
2919
2920 /*
2921  * Emits Optimized Code
2922  */
2923 static void emit_cfg(zend_op_array *op_array, BB* bb)
2924 {
2925   /* Compacting Optimized Code */
2926   BB* p = bb;
2927   zend_op* start = op_array->opcodes;
2928   zend_op* op = start;
2929   zend_op* end = op + op_array->last;
2930   while (p != NULL)
2931   {
2932     if (p->used)
2933         {
2934       if (p->len > 0 && op != p->start)
2935           {
2936         memmove(op, p->start, p->len * sizeof(zend_op));
2937       }
2938       p->start = op;
2939       op += p->len;
2940     }
2941     p = p->next;
2942   }
2943   op_array->last = op - start;
2944   op_array->start_op = NULL;
2945   while (op < end)
2946   {
2947     SET_TO_NOP(op);
2948     op++;
2949   }
2950
2951   /* Set Branch Targets */
2952   p = bb;
2953   while (p != NULL) {
2954     if (p->used && p->len > 0)
2955         {
2956       if (p->jmp_1 != NULL)
2957           {
2958         p->start[p->len-1].op1.u.opline_num = p->jmp_1->start - start;
2959       }
2960       if (p->jmp_2 != NULL)
2961           {
2962         p->start[p->len-1].op2.u.opline_num = p->jmp_2->start - start;
2963       }
2964       if (p->jmp_ext != NULL)
2965           {
2966         p->start[p->len-1].extended_value = p->jmp_ext->start - start;
2967       }
2968     }
2969     p = p->next;
2970   }
2971
2972         /*
2973          * HOESH: Reassign try & catch blocks
2974          */
2975         if (op_array->last_try_catch>0)
2976         {
2977                 int i;
2978                 int last_try_catch = op_array->last_try_catch;
2979                 zend_try_catch_element* old_tc_element = op_array->try_catch_array;
2980                 for (i=0; i<op_array->last_try_catch; i++, old_tc_element++)
2981                 {
2982                         if (bb[old_tc_element->try_op].used &&
2983                                 bb[old_tc_element->catch_op].used)
2984                         {
2985                                 old_tc_element->try_op = bb[old_tc_element->try_op].start - start;
2986                                 old_tc_element->catch_op = bb[old_tc_element->catch_op].start - start;
2987                         }
2988                         else
2989                         {
2990                                 old_tc_element->try_op = 0;
2991                                 old_tc_element->catch_op = 0;
2992                                 last_try_catch--;
2993                         }
2994                 }
2995                 if (op_array->last_try_catch > last_try_catch)
2996                 {
2997                         zend_try_catch_element* new_tc_array = NULL;
2998                         if (last_try_catch > 0)
2999                         {
3000                                 /* Lost some try & catch blocks */
3001                                 zend_try_catch_element* new_tc_element = emalloc(sizeof(zend_try_catch_element)*last_try_catch);
3002                                 new_tc_array = new_tc_element;
3003                                 old_tc_element = op_array->try_catch_array;
3004                                 for (i=0; i<op_array->last_try_catch; i++, old_tc_element++)
3005                                 {
3006                                         if (old_tc_element->try_op != old_tc_element->catch_op)
3007                                         {
3008                                                 new_tc_element->try_op = old_tc_element->try_op;
3009                                                 new_tc_element->catch_op = old_tc_element->catch_op;
3010                                                 new_tc_element++;
3011                                         }
3012                                 }
3013                         }
3014                         /* Otherwise lost all try & catch blocks */
3015                         efree(op_array->try_catch_array);
3016                         op_array->try_catch_array = new_tc_array;
3017                         op_array->last_try_catch = last_try_catch;
3018                 }
3019         }
3020 }
3021
3022 #define GET_REG(R) {\
3023                      if (assigned[(R)] < 0) {\
3024                        zend_uint j = 0;\
3025                        while (j < op_array->T) {\
3026                          if (reg_pool[j] == 0 &&\
3027                              (global[(R)] == 0 || used[j] == 0)) {\
3028                            reg_pool[j] = 1;\
3029                            assigned[(R)] = j;\
3030                            if (j+1 > n) {n = j+1;}\
3031                            break;\
3032                          }\
3033                          j++;\
3034                        }\
3035                      }\
3036                      used[assigned[(R)]] = 1;\
3037                    }
3038
3039 #define FREE_REG(R) reg_pool[(R)] = 0;
3040
3041
3042 void reassign_registers(zend_op_array *op_array, BB* p, char *global) {
3043   zend_uint i;
3044   zend_uint n = 0;
3045
3046 #ifdef ZEND_ENGINE_2_3
3047   int opline_num;
3048   int first_class_delayed = -1;
3049   int prev_class_delayed = -1;
3050   int last_class_delayed_in_prev_bb = -1;
3051   int last_class_delayed_in_this_bb = -1;
3052
3053   ALLOCA_FLAG(use_heap)
3054   int* assigned  = do_alloca(op_array->T * sizeof(int), use_heap);
3055   char* reg_pool = do_alloca(op_array->T * sizeof(char), use_heap);
3056   char* used     = do_alloca(op_array->T * sizeof(char), use_heap);
3057 #else
3058   int* assigned  = do_alloca(op_array->T * sizeof(int));
3059   char* reg_pool = do_alloca(op_array->T * sizeof(char));
3060   char* used     = do_alloca(op_array->T * sizeof(char));
3061 #endif
3062
3063   memset(assigned, -1, op_array->T * sizeof(int));
3064   memset(reg_pool, 0, op_array->T * sizeof(char));
3065   memset(used, 0, op_array->T * sizeof(char));
3066
3067   while (p != NULL) {
3068     if (p->used && p->len > 0) {
3069       zend_op* start = p->start;
3070       zend_op* op    = start + p->len;
3071       zend_op* op_data;
3072
3073       for (i = 0; i < op_array->T; i++) {
3074         if (!global[i]) {
3075           if (assigned[i] >= 0) {reg_pool[assigned[i]] = 0;}
3076           assigned[i] = -1;
3077         }
3078       }
3079
3080       while (start < op) {
3081         --op;
3082         op_data = NULL;
3083         if (op->opcode == ZEND_DO_FCALL_BY_NAME &&
3084             op->op1.op_type == IS_CONST) {
3085           zval_dtor(&op->op1.u.constant);
3086           op->op1.op_type = IS_UNUSED;
3087         }
3088         if (op->op1.op_type == IS_VAR || op->op1.op_type == IS_TMP_VAR) {
3089           int r = VAR_NUM(op->op1.u.var);
3090           GET_REG(r);
3091           if (op->opcode == ZEND_DO_FCALL_BY_NAME) {
3092             op->op1.op_type = IS_UNUSED;
3093           } else if (op->opcode == ZEND_FETCH_CONSTANT && op->op1.op_type == IS_VAR) {
3094             op->op1.u.var = VAR_VAL(assigned[r]);
3095 #ifndef ZEND_ENGINE_2_3
3096             /* restore op1 type from VAR to CONST (the opcode handler expects this or bombs out with invalid opcode)
3097                FETCH_CONSTANT when fetching class constant screws up because of this with >=php-5.3 */
3098             op->op1.op_type = IS_CONST;
3099 #endif
3100           } else {
3101             op->op1.u.var = VAR_VAL(assigned[r]);
3102           }
3103         }
3104         if (op->op2.op_type == IS_VAR || op->op2.op_type == IS_TMP_VAR) {
3105           int r = VAR_NUM(op->op2.u.var);
3106           GET_REG(r);
3107           op->op2.u.var = VAR_VAL(assigned[r]);
3108         }
3109 #ifdef ZEND_ENGINE_2_3
3110         if (op->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
3111           int r = VAR_NUM(op->extended_value);
3112           GET_REG(r);
3113           op->extended_value = VAR_VAL(assigned[r]);
3114
3115           opline_num = op - op_array->opcodes;
3116           /* store the very first occurence of ZEND_DECLARE_INHERITED_CLASS_DELAYED
3117              we need this to restore op_array->early_binding later on */
3118           if (first_class_delayed == -1)
3119             first_class_delayed = opline_num;
3120           if (last_class_delayed_in_this_bb == -1) {
3121             last_class_delayed_in_this_bb = opline_num;
3122           }
3123
3124           if (prev_class_delayed != -1) {
3125             /* link current ZEND_DECLARE_INHERITED_CLASS_DELAYED to previous one */
3126             op->result.u.opline_num = prev_class_delayed;
3127           }
3128           /* There might be another ZEND_DECLARE_INHERITED_CLASS_DELAYED down the road
3129              (or actually up the road since were traversing the oparray backwards).
3130              store current opline */
3131           prev_class_delayed = opline_num;
3132         }
3133 #endif
3134         if (op->opcode == ZEND_DECLARE_INHERITED_CLASS) {
3135
3136           int r = VAR_NUM(op->extended_value);
3137           GET_REG(r);
3138           op->extended_value = VAR_VAL(assigned[r]);
3139         }
3140         if (op->result.op_type == IS_VAR ||
3141             op->result.op_type == IS_TMP_VAR) {
3142           int r = VAR_NUM(op->result.u.var);
3143           GET_REG(r);
3144           op->result.u.var = VAR_VAL(assigned[r]);
3145           if (
3146               (op->opcode != ZEND_RECV && op->opcode != ZEND_RECV_INIT &&
3147               (op->result.u.EA.type & EXT_TYPE_UNUSED) != 0) ||
3148               (!(op->op1.op_type == op->result.op_type && op->op1.u.var == op->result.u.var) &&
3149               !(op->op2.op_type == op->result.op_type && op->op2.u.var == op->result.u.var) &&
3150               !global[r] && op->opcode != ZEND_ADD_ARRAY_ELEMENT )
3151              ) {
3152                 FREE_REG(VAR_NUM(op->result.u.var));
3153           }
3154         }
3155       }
3156     }
3157 #ifdef ZEND_ENGINE_2_3
3158     if (last_class_delayed_in_prev_bb != -1 && last_class_delayed_in_this_bb != -1) {
3159       op_array->opcodes[last_class_delayed_in_prev_bb].result.u.opline_num = prev_class_delayed;
3160       last_class_delayed_in_prev_bb = -1;
3161     }
3162     if (last_class_delayed_in_this_bb != -1) {
3163       last_class_delayed_in_prev_bb = last_class_delayed_in_this_bb;
3164       last_class_delayed_in_this_bb = -1;
3165     }
3166     prev_class_delayed = -1;
3167 #endif
3168    
3169     p = p->next;
3170   }
3171   op_array->T = n;
3172 #ifdef ZEND_ENGINE_2_3
3173   /* link back op_array->early_binding to the first occurance of ZEND_DECLARE_INHERITED_CLASS_DELAYED */
3174   if (first_class_delayed != -1)
3175     op_array->early_binding = first_class_delayed;
3176
3177   free_alloca(used, use_heap);
3178   free_alloca(reg_pool, use_heap);
3179   free_alloca(assigned, use_heap);
3180 #else
3181   free_alloca(used);
3182   free_alloca(reg_pool);
3183   free_alloca(assigned);
3184 #endif
3185 }
3186
3187 void restore_operand_types(zend_op_array *op_array) {
3188         zend_op* op = op_array->opcodes;
3189         int len = op_array->last;
3190         int line_num;
3191
3192         for (line_num=0; line_num < len; op++,line_num++)
3193         {
3194           if (op->opcode == ZEND_FETCH_CONSTANT && op->op1.op_type == IS_VAR) {
3195             /* restore op1 type from VAR to CONST (the opcode handler expects this or bombs out with invalid opcode) */
3196             op->op1.op_type = IS_CONST;
3197           }
3198         }
3199 }
3200
3201 #ifdef ZEND_ENGINE_2_3
3202 /*
3203  * Convert jmp_addrs back to opline_nums
3204  */
3205 void restore_opline_num(zend_op_array *op_array)
3206 {
3207     zend_op *opline, *end;
3208     opline = op_array->opcodes;
3209     end = opline + op_array->last;
3210    
3211     while (opline < end) {
3212         switch (opline->opcode){
3213             case ZEND_GOTO:
3214             case ZEND_JMP:
3215                 opline->op1.u.opline_num = opline->op1.u.jmp_addr - op_array->opcodes;
3216                 break;
3217             case ZEND_JMPZ:
3218             case ZEND_JMPNZ