PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - lcov_data/ext/opcache/Optimizer - block_pass.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 0 1097 0.0 %
Date: 2014-04-16 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 16 Apr 2014 12:48:02 +0000 (4 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.