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 - ext/opcache/Optimizer - block_pass.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 636 944 67.4 %
Date: 2017-10-15 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend OPcache                                                         |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2017 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Andi Gutmans <andi@zend.com>                                |
      16             :    |          Zeev Suraski <zeev@zend.com>                                |
      17             :    |          Stanislav Malyshev <stas@zend.com>                          |
      18             :    |          Dmitry Stogov <dmitry@zend.com>                             |
      19             :    +----------------------------------------------------------------------+
      20             : */
      21             : 
      22             : #include "php.h"
      23             : #include "Optimizer/zend_optimizer.h"
      24             : #include "Optimizer/zend_optimizer_internal.h"
      25             : #include "zend_API.h"
      26             : #include "zend_constants.h"
      27             : #include "zend_execute.h"
      28             : #include "zend_vm.h"
      29             : #include "zend_bitset.h"
      30             : #include "zend_cfg.h"
      31             : #include "zend_dump.h"
      32             : 
      33             : /* Checks if a constant (like "true") may be replaced by its value */
      34          64 : int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy)
      35             : {
      36             :         zend_constant *c;
      37             :         char *lookup_name;
      38          64 :         int retval = 1;
      39             :         ALLOCA_FLAG(use_heap);
      40             : 
      41         128 :         if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) {
      42          53 :                 lookup_name = do_alloca(ZSTR_LEN(name) + 1, use_heap);
      43          53 :                 memcpy(lookup_name, ZSTR_VAL(name), ZSTR_LEN(name) + 1);
      44          53 :                 zend_str_tolower(lookup_name, ZSTR_LEN(name));
      45             : 
      46         106 :                 if ((c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, ZSTR_LEN(name))) != NULL) {
      47           0 :                         if (!(c->flags & CONST_CT_SUBST) || (c->flags & CONST_CS)) {
      48           0 :                                 retval = 0;
      49             :                         }
      50             :                 } else {
      51          53 :                         retval = 0;
      52             :                 }
      53          53 :                 free_alloca(lookup_name, use_heap);
      54             :         }
      55             : 
      56          64 :         if (retval) {
      57          11 :                 if (c->flags & CONST_PERSISTENT) {
      58           1 :                         ZVAL_COPY_VALUE(result, &c->value);
      59           1 :                         if (copy) {
      60             :                                 zval_copy_ctor(result);
      61             :                         }
      62             :                 } else {
      63          10 :                         retval = 0;
      64             :                 }
      65             :         }
      66             : 
      67          64 :         return retval;
      68             : }
      69             : 
      70             : /* CFG back references management */
      71             : 
      72             : #define DEL_SOURCE(from, to)
      73             : #define ADD_SOURCE(from, to)
      74             : 
      75             : /* Data dependencies macros */
      76             : 
      77             : #define VAR_NUM_EX(op) VAR_NUM((op).var)
      78             : 
      79             : #define VAR_SOURCE(op) Tsource[VAR_NUM(op.var)]
      80             : #define SET_VAR_SOURCE(opline) Tsource[VAR_NUM(opline->result.var)] = opline
      81             : 
      82             : #define convert_to_string_safe(v) \
      83             :         if (Z_TYPE_P((v)) == IS_NULL) { \
      84             :                 ZVAL_STRINGL((v), "", 0); \
      85             :         } else { \
      86             :                 convert_to_string((v)); \
      87             :         }
      88             : 
      89       10308 : static void strip_leading_nops(zend_op_array *op_array, zend_basic_block *b)
      90             : {
      91       10308 :         zend_op *opcodes = op_array->opcodes;
      92             : 
      93       22677 :         while (b->len > 0 && opcodes[b->start].opcode == ZEND_NOP) {
      94             :             /* check if NOP breaks incorrect smart branch */
      95        3003 :                 if (b->len == 2
      96        2503 :                  && (op_array->opcodes[b->start + 1].opcode == ZEND_JMPZ
      97         867 :                   || op_array->opcodes[b->start + 1].opcode == ZEND_JMPNZ)
      98          27 :                  && (op_array->opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST))
      99             :                  && b->start > 0
     100          48 :                  && zend_is_smart_branch(op_array->opcodes + b->start - 1)) {
     101           0 :                         break;
     102             :                 }
     103        2061 :                 b->start++;
     104        2061 :                 b->len--;
     105             :         }
     106       10308 : }
     107             : 
     108        5154 : static void strip_nops(zend_op_array *op_array, zend_basic_block *b)
     109             : {
     110             :         uint32_t i, j;
     111             : 
     112        5154 :         strip_leading_nops(op_array, b);
     113        5154 :         if (b->len == 0) {
     114           6 :                 return;
     115             :         }
     116             : 
     117             :         /* strip the inside NOPs */
     118        5148 :         i = j = b->start + 1;
     119       30354 :         while (i < b->start + b->len) {
     120       20058 :                 if (op_array->opcodes[i].opcode != ZEND_NOP) {
     121       19733 :                         if (i != j) {
     122         629 :                                 op_array->opcodes[j] = op_array->opcodes[i];
     123             :                         }
     124       19733 :                         j++;
     125             :                 }
     126       73711 :                 if (i + 1 < b->start + b->len
     127       36745 :                  && (op_array->opcodes[i+1].opcode == ZEND_JMPZ
     128       32995 :                   || op_array->opcodes[i+1].opcode == ZEND_JMPNZ)
     129         528 :                  && op_array->opcodes[i+1].op1_type & (IS_CV|IS_CONST)
     130         600 :                  && zend_is_smart_branch(op_array->opcodes + j - 1)) {
     131             :                         /* don't remove NOP, that splits incorrect smart branch */
     132           0 :                         j++;
     133             :                 }
     134       20058 :                 i++;
     135             :         }
     136        5148 :         b->len = j - b->start;
     137       10621 :         while (j < i) {
     138         325 :                 MAKE_NOP(op_array->opcodes + j);
     139         325 :                 j++;
     140             :         }
     141             : }
     142             : 
     143        5154 : static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array, zend_bitset used_ext, zend_cfg *cfg, zend_op **Tsource)
     144             : {
     145             :         zend_op *opline, *src;
     146        5154 :         zend_op *end, *last_op = NULL;
     147             : 
     148             :         /* remove leading NOPs */
     149        5154 :         strip_leading_nops(op_array, block);
     150             : 
     151        5154 :         opline = op_array->opcodes + block->start;
     152        5154 :         end = opline + block->len;
     153       35522 :         while (opline < end) {
     154             :                 /* Constant Propagation: strip X = QM_ASSIGN(const) */
     155       30155 :                 if ((opline->op1_type & (IS_TMP_VAR|IS_VAR)) &&
     156        4941 :                     opline->opcode != ZEND_FREE) {
     157        4918 :                         src = VAR_SOURCE(opline->op1);
     158        9788 :                         if (src &&
     159        4857 :                             src->opcode == ZEND_QM_ASSIGN &&
     160          13 :                             src->op1_type == IS_CONST
     161             :                         ) {
     162          13 :                                 znode_op op1 = opline->op1;
     163          13 :                                 if (opline->opcode == ZEND_VERIFY_RETURN_TYPE) {
     164           0 :                                         COPY_NODE(opline->result, opline->op1);
     165           0 :                                         COPY_NODE(opline->op1, src->op1);
     166           0 :                                         VAR_SOURCE(op1) = NULL;
     167           0 :                                         MAKE_NOP(src);
     168          13 :                                 } else if (opline->opcode != ZEND_FETCH_LIST && opline->opcode != ZEND_CASE) {
     169          10 :                                         zval c = ZEND_OP1_LITERAL(src);
     170             :                                         zval_copy_ctor(&c);
     171          10 :                                         if (zend_optimizer_update_op1_const(op_array, opline, &c)) {
     172           4 :                                                 zend_optimizer_remove_live_range(op_array, op1.var);
     173           4 :                                                 VAR_SOURCE(op1) = NULL;
     174           8 :                                                 literal_dtor(&ZEND_OP1_LITERAL(src));
     175           4 :                                                 MAKE_NOP(src);
     176             :                                         }
     177             :                                 }
     178             :                         }
     179             :                 }
     180             : 
     181             :                 /* Constant Propagation: strip X = QM_ASSIGN(const) */
     182       25214 :                 if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
     183        1041 :                         src = VAR_SOURCE(opline->op2);
     184        2063 :                         if (src &&
     185        1021 :                             src->opcode == ZEND_QM_ASSIGN &&
     186           1 :                             src->op1_type == IS_CONST) {
     187             : 
     188           1 :                                 znode_op op2 = opline->op2;
     189           1 :                                 zval c = ZEND_OP1_LITERAL(src);
     190             : 
     191             :                                 zval_copy_ctor(&c);
     192           1 :                                 if (zend_optimizer_update_op2_const(op_array, opline, &c)) {
     193           0 :                                         zend_optimizer_remove_live_range(op_array, op2.var);
     194           0 :                                         VAR_SOURCE(op2) = NULL;
     195           0 :                                         literal_dtor(&ZEND_OP1_LITERAL(src));
     196           0 :                                         MAKE_NOP(src);
     197             :                                 }
     198             :                         }
     199             :                 }
     200             : 
     201       25214 :                 if (opline->opcode == ZEND_ECHO) {
     202         860 :                         if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
     203         225 :                                 src = VAR_SOURCE(opline->op1);
     204         447 :                                 if (src &&
     205         222 :                                     src->opcode == ZEND_CAST &&
     206           0 :                                     src->extended_value == IS_STRING) {
     207             :                                         /* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */
     208           0 :                                         VAR_SOURCE(opline->op1) = NULL;
     209           0 :                                         COPY_NODE(opline->op1, src->op1);
     210           0 :                                         MAKE_NOP(src);
     211             :                                 }
     212             :                         }
     213             : 
     214         860 :                         if (opline->op1_type == IS_CONST) {
     215         623 :                                 if (last_op && last_op->opcode == ZEND_ECHO &&
     216           1 :                                     last_op->op1_type == IS_CONST &&
     217           1 :                                     Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_DOUBLE &&
     218           1 :                                     Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_DOUBLE) {
     219             :                                         /* compress consecutive ECHO's.
     220             :                                          * Float to string conversion may be affected by current
     221             :                                          * locale setting.
     222             :                                          */
     223             :                                         int l, old_len;
     224             : 
     225           2 :                                         if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
     226           0 :                                                 convert_to_string_safe(&ZEND_OP1_LITERAL(opline));
     227             :                                         }
     228           2 :                                         if (Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_STRING) {
     229           0 :                                                 convert_to_string_safe(&ZEND_OP1_LITERAL(last_op));
     230             :                                         }
     231           1 :                                         old_len = Z_STRLEN(ZEND_OP1_LITERAL(last_op));
     232           1 :                                         l = old_len + Z_STRLEN(ZEND_OP1_LITERAL(opline));
     233           1 :                                         if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(last_op))) {
     234           0 :                                                 zend_string *tmp = zend_string_alloc(l, 0);
     235           0 :                                                 memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP1_LITERAL(last_op)), old_len);
     236           0 :                                                 Z_STR(ZEND_OP1_LITERAL(last_op)) = tmp;
     237             :                                         } else {
     238           2 :                                                 Z_STR(ZEND_OP1_LITERAL(last_op)) = zend_string_extend(Z_STR(ZEND_OP1_LITERAL(last_op)), l, 0);
     239             :                                         }
     240           1 :                                         Z_TYPE_INFO(ZEND_OP1_LITERAL(last_op)) = IS_STRING_EX;
     241           1 :                                         memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op)) + old_len, Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)));
     242           1 :                                         Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0';
     243           1 :                                         zval_dtor(&ZEND_OP1_LITERAL(opline));
     244           1 :                                         ZVAL_STR(&ZEND_OP1_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op))));
     245           1 :                                         ZVAL_NULL(&ZEND_OP1_LITERAL(last_op));
     246           1 :                                         MAKE_NOP(last_op);
     247             :                                 }
     248         620 :                                 last_op = opline;
     249             :                         } else {
     250         240 :                                 last_op = NULL;
     251             :                         }
     252             :                 } else {
     253       24354 :                         last_op = NULL;
     254             :                 }
     255             : 
     256       25214 :                 switch (opline->opcode) {
     257             : 
     258             :                         case ZEND_FREE:
     259          23 :                                 if (opline->op1_type == IS_TMP_VAR) {
     260          16 :                                         src = VAR_SOURCE(opline->op1);
     261          42 :                                         if (src &&
     262          26 :                                             (src->opcode == ZEND_BOOL || src->opcode == ZEND_BOOL_NOT)) {
     263             :                                                 /* T = BOOL(X), FREE(T) => T = BOOL(X) */
     264             :                                                 /* The remaining BOOL is removed by a separate optimization */
     265           0 :                                                 VAR_SOURCE(opline->op1) = NULL;
     266           0 :                                                 MAKE_NOP(opline);
     267             :                                         }
     268           7 :                                 } else if (opline->op1_type == IS_VAR) {
     269           7 :                                         src = VAR_SOURCE(opline->op1);
     270             :                                         /* V = OP, FREE(V) => OP. NOP */
     271          23 :                                         if (src &&
     272           4 :                                             src->opcode != ZEND_FETCH_R &&
     273           4 :                                             src->opcode != ZEND_FETCH_STATIC_PROP_R &&
     274           4 :                                             src->opcode != ZEND_FETCH_DIM_R &&
     275           2 :                                             src->opcode != ZEND_FETCH_OBJ_R &&
     276           2 :                                             src->opcode != ZEND_NEW) {
     277           0 :                                                 if (opline->extended_value & ZEND_FREE_ON_RETURN) {
     278             :                                                         /* mark as removed (empty live range) */
     279           0 :                                                         op_array->live_range[opline->op2.num].var = (uint32_t)-1;
     280             :                                                 }
     281           0 :                                                 ZEND_RESULT_TYPE(src) = IS_UNUSED;
     282           0 :                                                 MAKE_NOP(opline);
     283             :                                         }
     284             :                                 }
     285          23 :                                 break;
     286             : 
     287             : #if 0
     288             :                 /* pre-evaluate functions:
     289             :                    constant(x)
     290             :                    defined(x)
     291             :                    function_exists(x)
     292             :                    extension_loaded(x)
     293             :                    BAD: interacts badly with Accelerator
     294             :                 */
     295             :                 if((ZEND_OP1_TYPE(opline) & IS_VAR) &&
     296             :                    VAR_SOURCE(opline->op1) && VAR_SOURCE(opline->op1)->opcode == ZEND_DO_CF_FCALL &&
     297             :                    VAR_SOURCE(opline->op1)->extended_value == 1) {
     298             :                         zend_op *fcall = VAR_SOURCE(opline->op1);
     299             :                         zend_op *sv = fcall-1;
     300             :                         if(sv >= block->start_opline && sv->opcode == ZEND_SEND_VAL &&
     301             :                            ZEND_OP1_TYPE(sv) == IS_CONST && Z_TYPE(OPLINE_OP1_LITERAL(sv)) == IS_STRING &&
     302             :                            Z_LVAL(OPLINE_OP2_LITERAL(sv)) == 1
     303             :                            ) {
     304             :                                 zval *arg = &OPLINE_OP1_LITERAL(sv);
     305             :                                 char *fname = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].function_name;
     306             :                                 int flen = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].name_len;
     307             :                                 if(flen == sizeof("defined")-1 && zend_binary_strcasecmp(fname, flen, "defined", sizeof("defined")-1) == 0) {
     308             :                                         zval c;
     309             :                                         if(zend_optimizer_get_persistent_constant(Z_STR_P(arg), &c, 0 ELS_CC) != 0) {
     310             :                                                 literal_dtor(arg);
     311             :                                                 MAKE_NOP(sv);
     312             :                                                 MAKE_NOP(fcall);
     313             :                                                 LITERAL_BOOL(opline->op1, 1);
     314             :                                                 ZEND_OP1_TYPE(opline) = IS_CONST;
     315             :                                         }
     316             :                                 } else if((flen == sizeof("function_exists")-1 && zend_binary_strcasecmp(fname, flen, "function_exists", sizeof("function_exists")-1) == 0) ||
     317             :                                                   (flen == sizeof("is_callable")-1 && zend_binary_strcasecmp(fname, flen, "is_callable", sizeof("is_callable")-1) == 0)
     318             :                                                   ) {
     319             :                                         zend_function *function;
     320             :                                         if((function = zend_hash_find_ptr(EG(function_table), Z_STR_P(arg))) != NULL) {
     321             :                                                 literal_dtor(arg);
     322             :                                                 MAKE_NOP(sv);
     323             :                                                 MAKE_NOP(fcall);
     324             :                                                 LITERAL_BOOL(opline->op1, 1);
     325             :                                                 ZEND_OP1_TYPE(opline) = IS_CONST;
     326             :                                         }
     327             :                                 } else if(flen == sizeof("constant")-1 && zend_binary_strcasecmp(fname, flen, "constant", sizeof("constant")-1) == 0) {
     328             :                                         zval c;
     329             :                                         if(zend_optimizer_get_persistent_constant(Z_STR_P(arg), &c, 1 ELS_CC) != 0) {
     330             :                                                 literal_dtor(arg);
     331             :                                                 MAKE_NOP(sv);
     332             :                                                 MAKE_NOP(fcall);
     333             :                                                 ZEND_OP1_LITERAL(opline) = zend_optimizer_add_literal(op_array, &c);
     334             :                                                 /* no copy ctor - get already copied it */
     335             :                                                 ZEND_OP1_TYPE(opline) = IS_CONST;
     336             :                                         }
     337             :                                 } else if(flen == sizeof("extension_loaded")-1 && zend_binary_strcasecmp(fname, flen, "extension_loaded", sizeof("extension_loaded")-1) == 0) {
     338             :                                         if(zend_hash_exists(&module_registry, Z_STR_P(arg))) {
     339             :                                                 literal_dtor(arg);
     340             :                                                 MAKE_NOP(sv);
     341             :                                                 MAKE_NOP(fcall);
     342             :                                                 LITERAL_BOOL(opline->op1, 1);
     343             :                                                 ZEND_OP1_TYPE(opline) = IS_CONST;
     344             :                                         }
     345             :                                 }
     346             :                         }
     347             :                 }
     348             : #endif
     349             : 
     350             :                         case ZEND_FETCH_LIST:
     351          21 :                                 if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
     352             :                                         /* LIST variable will be deleted later by FREE */
     353           9 :                                         Tsource[VAR_NUM(opline->op1.var)] = NULL;
     354             :                                 }
     355          21 :                                 break;
     356             : 
     357             :                         case ZEND_CASE:
     358          63 :                                 if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
     359             :                                         /* CASE variable will be deleted later by FREE, so we can't optimize it */
     360           0 :                                         Tsource[VAR_NUM(opline->op1.var)] = NULL;
     361           0 :                                         break;
     362             :                                 }
     363         117 :                                 if (opline->op1_type == IS_CONST &&
     364          54 :                                     opline->op2_type == IS_CONST) {
     365          54 :                                         break;
     366             :                                 }
     367             :                                 /* break missing intentionally */
     368             : 
     369             :                         case ZEND_IS_EQUAL:
     370             :                         case ZEND_IS_NOT_EQUAL:
     371         141 :                                 if (opline->op1_type == IS_CONST &&
     372           0 :                                     opline->op2_type == IS_CONST) {
     373           0 :                                         goto optimize_constant_binary_op;
     374             :                                 }
     375             :                         /* IS_EQ(TRUE, X)      => BOOL(X)
     376             :                          * IS_EQ(FALSE, X)     => BOOL_NOT(X)
     377             :                          * IS_NOT_EQ(TRUE, X)  => BOOL_NOT(X)
     378             :                          * IS_NOT_EQ(FALSE, X) => BOOL(X)
     379             :                          * CASE(TRUE, X)       => BOOL(X)
     380             :                          * CASE(FALSE, X)      => BOOL_NOT(X)
     381             :                          */
     382         141 :                                 if (opline->op1_type == IS_CONST &&
     383           0 :                                         (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_FALSE ||
     384           0 :                                          Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_TRUE)) {
     385             :                                         /* Optimization of comparison with "null" is not safe,
     386             :                                          * because ("0" == null) is not equal to !("0")
     387             :                                          */
     388           0 :                                         opline->opcode =
     389           0 :                                                 ((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP1_LITERAL(opline))) == IS_TRUE)) ?
     390             :                                                 ZEND_BOOL : ZEND_BOOL_NOT;
     391           0 :                                         COPY_NODE(opline->op1, opline->op2);
     392           0 :                                         SET_UNUSED(opline->op2);
     393           0 :                                         goto optimize_bool;
     394         345 :                                 } else if (opline->op2_type == IS_CONST &&
     395         102 :                                            (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_FALSE ||
     396         102 :                                             Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_TRUE)) {
     397             :                                         /* Optimization of comparison with "null" is not safe,
     398             :                                          * because ("0" == null) is not equal to !("0")
     399             :                                          */
     400           0 :                                         opline->opcode =
     401           0 :                                                 ((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP2_LITERAL(opline))) == IS_TRUE)) ?
     402             :                                                 ZEND_BOOL : ZEND_BOOL_NOT;
     403           0 :                                         SET_UNUSED(opline->op2);
     404           0 :                                         goto optimize_bool;
     405             :                                 }
     406         141 :                                 break;
     407             : 
     408             :                         case ZEND_BOOL:
     409             :                         case ZEND_BOOL_NOT:
     410             :                         optimize_bool:
     411         155 :                                 if (opline->op1_type == IS_CONST) {
     412           2 :                                         goto optimize_const_unary_op;
     413             :                                 }
     414         189 :                                 if (opline->op1_type == IS_TMP_VAR &&
     415          36 :                                     !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
     416          27 :                                         src = VAR_SOURCE(opline->op1);
     417          27 :                                         if (src) {
     418          27 :                                                 switch (src->opcode) {
     419             :                                                         case ZEND_BOOL_NOT:
     420             :                                                                 /* T = BOOL_NOT(X) + BOOL(T) -> NOP, BOOL_NOT(X) */
     421          19 :                                                                 VAR_SOURCE(opline->op1) = NULL;
     422          19 :                                                                 COPY_NODE(opline->op1, src->op1);
     423          19 :                                                                 opline->opcode = (opline->opcode == ZEND_BOOL) ? ZEND_BOOL_NOT : ZEND_BOOL;
     424          19 :                                                                 MAKE_NOP(src);
     425          19 :                                                                 goto optimize_bool;
     426             :                                                         case ZEND_BOOL:
     427             :                                                                 /* T = BOOL(X) + BOOL(T) -> NOP, BOOL(X) */
     428           0 :                                                                 VAR_SOURCE(opline->op1) = NULL;
     429           0 :                                                                 COPY_NODE(opline->op1, src->op1);
     430           0 :                                                                 MAKE_NOP(src);
     431           0 :                                                                 goto optimize_bool;
     432             :                                                         case ZEND_IS_EQUAL:
     433           2 :                                                                 if (opline->opcode == ZEND_BOOL_NOT) {
     434           0 :                                                                         src->opcode = ZEND_IS_NOT_EQUAL;
     435             :                                                                 }
     436           2 :                                                                 COPY_NODE(src->result, opline->result);
     437           2 :                                                                 SET_VAR_SOURCE(src);
     438           2 :                                                                 MAKE_NOP(opline);
     439           2 :                                                                 break;
     440             :                                                         case ZEND_IS_NOT_EQUAL:
     441           2 :                                                                 if (opline->opcode == ZEND_BOOL_NOT) {
     442           0 :                                                                         src->opcode = ZEND_IS_EQUAL;
     443             :                                                                 }
     444           2 :                                                                 COPY_NODE(src->result, opline->result);
     445           2 :                                                                 SET_VAR_SOURCE(src);
     446           2 :                                                                 MAKE_NOP(opline);
     447           2 :                                                                 break;
     448             :                                                         case ZEND_IS_IDENTICAL:
     449           0 :                                                                 if (opline->opcode == ZEND_BOOL_NOT) {
     450           0 :                                                                         src->opcode = ZEND_IS_NOT_IDENTICAL;
     451             :                                                                 }
     452           0 :                                                                 COPY_NODE(src->result, opline->result);
     453           0 :                                                                 SET_VAR_SOURCE(src);
     454           0 :                                                                 MAKE_NOP(opline);
     455           0 :                                                                 break;
     456             :                                                         case ZEND_IS_NOT_IDENTICAL:
     457           0 :                                                                 if (opline->opcode == ZEND_BOOL_NOT) {
     458           0 :                                                                         src->opcode = ZEND_IS_IDENTICAL;
     459             :                                                                 }
     460           0 :                                                                 COPY_NODE(src->result, opline->result);
     461           0 :                                                                 SET_VAR_SOURCE(src);
     462           0 :                                                                 MAKE_NOP(opline);
     463           0 :                                                                 break;
     464             :                                                         case ZEND_IS_SMALLER:
     465           2 :                                                                 if (opline->opcode == ZEND_BOOL_NOT) {
     466             :                                                                         zend_uchar tmp_type;
     467             :                                                                         uint32_t tmp;
     468             : 
     469           0 :                                                                         src->opcode = ZEND_IS_SMALLER_OR_EQUAL;
     470           0 :                                                                         tmp_type = src->op1_type;
     471           0 :                                                                         src->op1_type = src->op2_type;
     472           0 :                                                                         src->op2_type = tmp_type;
     473           0 :                                                                         tmp = src->op1.num;
     474           0 :                                                                         src->op1.num = src->op2.num;
     475           0 :                                                                         src->op2.num = tmp;
     476             :                                                                 }
     477           2 :                                                                 COPY_NODE(src->result, opline->result);
     478           2 :                                                                 SET_VAR_SOURCE(src);
     479           2 :                                                                 MAKE_NOP(opline);
     480           2 :                                                                 break;
     481             :                                                         case ZEND_IS_SMALLER_OR_EQUAL:
     482           0 :                                                                 if (opline->opcode == ZEND_BOOL_NOT) {
     483             :                                                                         zend_uchar tmp_type;
     484             :                                                                         uint32_t tmp;
     485             : 
     486           0 :                                                                         src->opcode = ZEND_IS_SMALLER;
     487           0 :                                                                         tmp_type = src->op1_type;
     488           0 :                                                                         src->op1_type = src->op2_type;
     489           0 :                                                                         src->op2_type = tmp_type;
     490           0 :                                                                         tmp = src->op1.num;
     491           0 :                                                                         src->op1.num = src->op2.num;
     492           0 :                                                                         src->op2.num = tmp;
     493             :                                                                 }
     494           0 :                                                                 COPY_NODE(src->result, opline->result);
     495           0 :                                                                 SET_VAR_SOURCE(src);
     496           0 :                                                                 MAKE_NOP(opline);
     497           0 :                                                                 break;
     498             :                                                         case ZEND_ISSET_ISEMPTY_VAR:
     499             :                                                         case ZEND_ISSET_ISEMPTY_DIM_OBJ:
     500             :                                                         case ZEND_ISSET_ISEMPTY_PROP_OBJ:
     501             :                                                         case ZEND_ISSET_ISEMPTY_STATIC_PROP:
     502             :                                                         case ZEND_INSTANCEOF:
     503             :                                                         case ZEND_TYPE_CHECK:
     504             :                                                         case ZEND_DEFINED:
     505           2 :                                                                 if (opline->opcode == ZEND_BOOL_NOT) {
     506           1 :                                                                         break;
     507             :                                                                 }
     508           1 :                                                                 COPY_NODE(src->result, opline->result);
     509           1 :                                                                 SET_VAR_SOURCE(src);
     510           1 :                                                                 MAKE_NOP(opline);
     511             :                                                                 break;
     512             :                                                 }
     513             :                                         }
     514             :                                 }
     515         134 :                                 break;
     516             : 
     517             :                         case ZEND_JMPZ:
     518             :                         case ZEND_JMPNZ:
     519             :                         case ZEND_JMPZ_EX:
     520             :                         case ZEND_JMPNZ_EX:
     521             :                         case ZEND_JMPZNZ:
     522             :                         optimize_jmpznz:
     523        1435 :                                 if (opline->op1_type == IS_TMP_VAR &&
     524         467 :                                     (!zend_bitset_in(used_ext, VAR_NUM(opline->op1.var)) ||
     525          19 :                                      (opline->result_type == opline->op1_type &&
     526           9 :                                       opline->result.var == opline->op1.var))) {
     527         457 :                                         src = VAR_SOURCE(opline->op1);
     528         457 :                                         if (src) {
     529         599 :                                                 if (src->opcode == ZEND_BOOL_NOT &&
     530          71 :                                                     opline->opcode != ZEND_JMPZ_EX &&
     531          71 :                                                     opline->opcode != ZEND_JMPNZ_EX) {
     532          71 :                                                         VAR_SOURCE(opline->op1) = NULL;
     533          71 :                                                         COPY_NODE(opline->op1, src->op1);
     534          71 :                                                         if (opline->opcode == ZEND_JMPZ) {
     535             :                                                                 /* T = BOOL_NOT(X) + JMPZ(T) -> NOP, JMPNZ(X) */
     536          62 :                                                                 opline->opcode = ZEND_JMPNZ;
     537           9 :                                                         } else if (opline->opcode == ZEND_JMPNZ) {
     538             :                                                                 /* T = BOOL_NOT(X) + JMPNZ(T) -> NOP, JMPZ(X) */
     539           6 :                                                                 opline->opcode = ZEND_JMPZ;
     540             : #if 0
     541             :                                                         } else if (opline->opcode == ZEND_JMPZ_EX) {
     542             :                                                                 /* T = BOOL_NOT(X) + JMPZ_EX(T) -> NOP, JMPNZ_EX(X) */
     543             :                                                                 opline->opcode = ZEND_JMPNZ_EX;
     544             :                                                         } else if (opline->opcode == ZEND_JMPNZ_EX) {
     545             :                                                                 /* T = BOOL_NOT(X) + JMPNZ_EX(T) -> NOP, JMPZ_EX(X) */
     546             :                                                                 opline->opcode = ZEND_JMPZ;
     547             : #endif
     548             :                                                         } else {
     549             :                                                                 /* T = BOOL_NOT(X) + JMPZNZ(T,L1,L2) -> NOP, JMPZNZ(X,L2,L1) */
     550             :                                                                 uint32_t tmp;
     551             : 
     552             :                                                                 ZEND_ASSERT(opline->opcode == ZEND_JMPZNZ);
     553           3 :                                                                 tmp = block->successors[0];
     554           3 :                                                                 block->successors[0] = block->successors[1];
     555           3 :                                                                 block->successors[1] = tmp;
     556             :                                                         }
     557          71 :                                                         MAKE_NOP(src);
     558          71 :                                                         goto optimize_jmpznz;
     559         748 :                                                 } else if (src->opcode == ZEND_BOOL ||
     560         362 :                                                            src->opcode == ZEND_QM_ASSIGN) {
     561          24 :                                                         VAR_SOURCE(opline->op1) = NULL;
     562          24 :                                                         COPY_NODE(opline->op1, src->op1);
     563          24 :                                                         MAKE_NOP(src);
     564          24 :                                                         goto optimize_jmpznz;
     565             :                                                 }
     566             :                                         }
     567             :                                 }
     568         845 :                                 break;
     569             : 
     570             :                         case ZEND_CONCAT:
     571             :                         case ZEND_FAST_CONCAT:
     572         576 :                                 if (opline->op1_type == IS_CONST &&
     573         147 :                                     opline->op2_type == IS_CONST) {
     574           0 :                                         goto optimize_constant_binary_op;
     575             :                                 }
     576             : 
     577         645 :                                 if (opline->op2_type == IS_CONST &&
     578         216 :                                     opline->op1_type == IS_TMP_VAR) {
     579             : 
     580          99 :                                         src = VAR_SOURCE(opline->op1);
     581         333 :                                     if (src &&
     582          99 :                                             (src->opcode == ZEND_CONCAT ||
     583          45 :                                              src->opcode == ZEND_FAST_CONCAT) &&
     584          90 :                                             src->op2_type == IS_CONST) {
     585             :                                                 /* compress consecutive CONCATs */
     586             :                                                 int l, old_len;
     587             : 
     588           0 :                                                 if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
     589           0 :                                                         convert_to_string_safe(&ZEND_OP2_LITERAL(opline));
     590             :                                                 }
     591           0 :                                                 if (Z_TYPE(ZEND_OP2_LITERAL(src)) != IS_STRING) {
     592           0 :                                                         convert_to_string_safe(&ZEND_OP2_LITERAL(src));
     593             :                                                 }
     594             : 
     595           0 :                                                 VAR_SOURCE(opline->op1) = NULL;
     596           0 :                                                 COPY_NODE(opline->op1, src->op1);
     597           0 :                                                 old_len = Z_STRLEN(ZEND_OP2_LITERAL(src));
     598           0 :                                                 l = old_len + Z_STRLEN(ZEND_OP2_LITERAL(opline));
     599           0 :                                                 if (!Z_REFCOUNTED(ZEND_OP2_LITERAL(src))) {
     600           0 :                                                         zend_string *tmp = zend_string_alloc(l, 0);
     601           0 :                                                         memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP2_LITERAL(src)), old_len);
     602           0 :                                                         Z_STR(ZEND_OP2_LITERAL(src)) = tmp;
     603             :                                                 } else {
     604           0 :                                                         Z_STR(ZEND_OP2_LITERAL(src)) = zend_string_extend(Z_STR(ZEND_OP2_LITERAL(src)), l, 0);
     605             :                                                 }
     606           0 :                                                 Z_TYPE_INFO(ZEND_OP2_LITERAL(src)) = IS_STRING_EX;
     607           0 :                                                 memcpy(Z_STRVAL(ZEND_OP2_LITERAL(src)) + old_len, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
     608           0 :                                                 Z_STRVAL(ZEND_OP2_LITERAL(src))[l] = '\0';
     609           0 :                                                 zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline)));
     610           0 :                                                 ZVAL_STR(&ZEND_OP2_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP2_LITERAL(src))));
     611           0 :                                                 ZVAL_NULL(&ZEND_OP2_LITERAL(src));
     612           0 :                                                 MAKE_NOP(src);
     613             :                                         }
     614             :                                 }
     615             : 
     616         429 :                                 if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
     617         210 :                                         src = VAR_SOURCE(opline->op1);
     618         420 :                                         if (src &&
     619         210 :                                             src->opcode == ZEND_CAST &&
     620           0 :                                             src->extended_value == IS_STRING) {
     621             :                                                 /* convert T1 = CAST(STRING, X), T2 = CONCAT(T1, Y) to T2 = CONCAT(X,Y) */
     622           0 :                                                 VAR_SOURCE(opline->op1) = NULL;
     623           0 :                                                 COPY_NODE(opline->op1, src->op1);
     624           0 :                                                 MAKE_NOP(src);
     625             :                                         }
     626             :                     }
     627         429 :                                 if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
     628         171 :                                         src = VAR_SOURCE(opline->op2);
     629         342 :                                         if (src &&
     630         171 :                                             src->opcode == ZEND_CAST &&
     631           0 :                                             src->extended_value == IS_STRING) {
     632             :                                                 /* convert T1 = CAST(STRING, X), T2 = CONCAT(Y, T1) to T2 = CONCAT(Y,X) */
     633           0 :                                                 zend_op *src = VAR_SOURCE(opline->op2);
     634           0 :                                                 VAR_SOURCE(opline->op2) = NULL;
     635           0 :                                                 COPY_NODE(opline->op2, src->op1);
     636           0 :                                                 MAKE_NOP(src);
     637             :                                         }
     638             :                                 }
     639         723 :                                 if (opline->op1_type == IS_CONST &&
     640         147 :                                     Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
     641         147 :                                     Z_STRLEN(ZEND_OP1_LITERAL(opline)) == 0) {
     642             :                                         /* convert CONCAT('', X) => CAST(STRING, X) */
     643           0 :                                         literal_dtor(&ZEND_OP1_LITERAL(opline));
     644           0 :                                         opline->opcode = ZEND_CAST;
     645           0 :                                         opline->extended_value = IS_STRING;
     646           0 :                                         COPY_NODE(opline->op1, opline->op2);
     647           0 :                                         opline->op2_type = IS_UNUSED;
     648           0 :                                         opline->op2.var = 0;
     649         861 :                                 } else if (opline->op2_type == IS_CONST &&
     650         216 :                                    Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
     651         216 :                                    Z_STRLEN(ZEND_OP2_LITERAL(opline)) == 0) {
     652             :                                         /* convert CONCAT(X, '') => CAST(STRING, X) */
     653           0 :                                         literal_dtor(&ZEND_OP2_LITERAL(opline));
     654           0 :                                         opline->opcode = ZEND_CAST;
     655           0 :                                         opline->extended_value = IS_STRING;
     656           0 :                                         opline->op2_type = IS_UNUSED;
     657           0 :                                         opline->op2.var = 0;
     658        1820 :                                 } else if (opline->opcode == ZEND_CONCAT &&
     659         298 :                                            (opline->op1_type == IS_CONST ||
     660         192 :                                             (opline->op1_type == IS_TMP_VAR &&
     661         120 :                                              VAR_SOURCE(opline->op1) &&
     662         120 :                                              (VAR_SOURCE(opline->op1)->opcode == ZEND_FAST_CONCAT ||
     663         102 :                                               VAR_SOURCE(opline->op1)->opcode == ZEND_ROPE_END ||
     664          96 :                                               VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CONSTANT ||
     665          93 :                                               VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CLASS_CONSTANT))) &&
     666         133 :                                            (opline->op2_type == IS_CONST ||
     667         118 :                                             (opline->op2_type == IS_TMP_VAR &&
     668          28 :                                              VAR_SOURCE(opline->op2) &&
     669          28 :                                              (VAR_SOURCE(opline->op2)->opcode == ZEND_FAST_CONCAT ||
     670          28 :                                               VAR_SOURCE(opline->op2)->opcode == ZEND_ROPE_END ||
     671          28 :                                               VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CONSTANT ||
     672           7 :                                               VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CLASS_CONSTANT)))) {
     673          37 :                                         opline->opcode = ZEND_FAST_CONCAT;
     674             :                                 }
     675         429 :                                 break;
     676             : 
     677             :                         case ZEND_ADD:
     678             :                         case ZEND_SUB:
     679             :                         case ZEND_MUL:
     680             :                         case ZEND_DIV:
     681             :                         case ZEND_MOD:
     682             :                         case ZEND_SL:
     683             :                         case ZEND_SR:
     684             :                         case ZEND_IS_SMALLER:
     685             :                         case ZEND_IS_SMALLER_OR_EQUAL:
     686             :                         case ZEND_IS_IDENTICAL:
     687             :                         case ZEND_IS_NOT_IDENTICAL:
     688             :                         case ZEND_BOOL_XOR:
     689             :                         case ZEND_BW_OR:
     690             :                         case ZEND_BW_AND:
     691             :                         case ZEND_BW_XOR:
     692         237 :                                 if (opline->op1_type == IS_CONST &&
     693          33 :                                     opline->op2_type == IS_CONST) {
     694             :                                         /* evaluate constant expressions */
     695             :                                         binary_op_type binary_op;
     696             :                                         zval result;
     697             :                                         int er;
     698             : 
     699             : optimize_constant_binary_op:
     700           0 :                                         binary_op = get_binary_op(opline->opcode);
     701           0 :                             if ((opline->opcode == ZEND_DIV || opline->opcode == ZEND_MOD) &&
     702           0 :                                 zval_get_long(&ZEND_OP2_LITERAL(opline)) == 0) {
     703           0 :                                                 SET_VAR_SOURCE(opline);
     704           0 :                                 opline++;
     705           0 :                                                 continue;
     706           0 :                             } else if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR) &&
     707           0 :                                 zval_get_long(&ZEND_OP2_LITERAL(opline)) < 0) {
     708           0 :                                                 SET_VAR_SOURCE(opline);
     709           0 :                                 opline++;
     710           0 :                                                 continue;
     711           0 :                                         } else if (zend_binary_op_produces_numeric_string_error(opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline))) {
     712           0 :                                                 SET_VAR_SOURCE(opline);
     713           0 :                                 opline++;
     714           0 :                                                 continue;
     715             :                                         }
     716           0 :                                         er = EG(error_reporting);
     717           0 :                                         EG(error_reporting) = 0;
     718           0 :                                         if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
     719           0 :                                                 literal_dtor(&ZEND_OP1_LITERAL(opline));
     720           0 :                                                 literal_dtor(&ZEND_OP2_LITERAL(opline));
     721           0 :                                                 opline->opcode = ZEND_QM_ASSIGN;
     722           0 :                                                 SET_UNUSED(opline->op2);
     723           0 :                                                 zend_optimizer_update_op1_const(op_array, opline, &result);
     724             :                                         }
     725           0 :                                         EG(error_reporting) = er;
     726             :                                 }
     727         204 :                                 break;
     728             : 
     729             :                         case ZEND_BW_NOT:
     730           9 :                                 if (opline->op1_type == IS_CONST) {
     731             :                                         /* evaluate constant unary ops */
     732             :                                         unary_op_type unary_op;
     733             :                                         zval result;
     734             : 
     735             : optimize_const_unary_op:
     736           2 :                                         unary_op = get_unary_op(opline->opcode);
     737           2 :                                         if (unary_op) {
     738           0 :                                                 unary_op(&result, &ZEND_OP1_LITERAL(opline));
     739           0 :                                                 literal_dtor(&ZEND_OP1_LITERAL(opline));
     740             :                                         } else {
     741             :                                                 /* BOOL */
     742           2 :                                                 ZVAL_COPY_VALUE(&result, &ZEND_OP1_LITERAL(opline));
     743           2 :                                                 convert_to_boolean(&result);
     744           2 :                                                 ZVAL_NULL(&ZEND_OP1_LITERAL(opline));
     745             :                                         }
     746           2 :                                         opline->opcode = ZEND_QM_ASSIGN;
     747           2 :                                         zend_optimizer_update_op1_const(op_array, opline, &result);
     748             :                                 }
     749          11 :                                 break;
     750             : 
     751             :                         case ZEND_RETURN:
     752             :                         case ZEND_EXIT:
     753        2497 :                                 if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
     754         159 :                                         src = VAR_SOURCE(opline->op1);
     755         159 :                                         if (src && src->opcode == ZEND_QM_ASSIGN) {
     756           0 :                                                 zend_op *op = src + 1;
     757           0 :                                                 zend_bool optimize = 1;
     758             : 
     759           0 :                                                 while (op < opline) {
     760           0 :                                                         if ((op->op1_type == opline->op1_type
     761           0 :                                                           && op->op1.var == opline->op1.var)
     762             :                                                          || (op->op2_type == opline->op1_type
     763           0 :                                                           && op->op2.var == opline->op1.var)) {
     764           0 :                                                                 optimize = 0;
     765           0 :                                                                 break;
     766             :                                                         }
     767           0 :                                                         op++;
     768             :                                                 }
     769             : 
     770           0 :                                                 if (optimize) {
     771             :                                                         /* T = QM_ASSIGN(X), RETURN(T) to NOP, RETURN(X) */
     772           0 :                                                         VAR_SOURCE(opline->op1) = NULL;
     773           0 :                                                         COPY_NODE(opline->op1, src->op1);
     774           0 :                                                         MAKE_NOP(src);
     775             :                                                 }
     776             :                                         }
     777             :                                 }
     778        2497 :                                 break;
     779             : 
     780             :                         case ZEND_QM_ASSIGN:
     781          62 :                                 if (opline->op1_type == opline->result_type &&
     782           3 :                                     opline->op1.var == opline->result.var) {
     783             :                                         /* strip T = QM_ASSIGN(T) */
     784           0 :                                         MAKE_NOP(opline);
     785             :                                 }
     786             :                                 break;
     787             :                 }
     788             : 
     789             :                 /* get variable source */
     790       25214 :                 if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
     791        6180 :                         SET_VAR_SOURCE(opline);
     792             :                 }
     793       25214 :                 opline++;
     794             :         }
     795             : 
     796        5154 :         strip_nops(op_array, block);
     797        5154 : }
     798             : 
     799             : /* Rebuild plain (optimized) op_array from CFG */
     800         726 : static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array)
     801             : {
     802         726 :         zend_basic_block *blocks = cfg->blocks;
     803         726 :         zend_basic_block *end = blocks + cfg->blocks_count;
     804             :         zend_basic_block *b;
     805             :         zend_op *new_opcodes;
     806             :         zend_op *opline;
     807         726 :         uint32_t len = 0;
     808             :         int n;
     809             : 
     810        3042 :         for (b = blocks; b < end; b++) {
     811        2316 :                 if (b->len == 0) {
     812         621 :                         continue;
     813             :                 }
     814        1695 :                 if (b->flags & ZEND_BB_REACHABLE) {
     815        1576 :                         opline = op_array->opcodes + b->start + b->len - 1;
     816        1576 :                         if (opline->opcode == ZEND_JMP) {
     817          46 :                                 zend_basic_block *next = b + 1;
     818             : 
     819          95 :                                 while (next < end && !(next->flags & ZEND_BB_REACHABLE)) {
     820           3 :                                         next++;
     821             :                                 }
     822          46 :                                 if (next < end && next == blocks + b->successors[0]) {
     823             :                                         /* JMP to the next block - strip it */
     824           0 :                                         MAKE_NOP(opline);
     825           0 :                                         b->len--;
     826             :                                 }
     827        1530 :                         } else if (b->len == 1 && opline->opcode == ZEND_NOP) {
     828             :                                 /* skip empty block */
     829           0 :                                 b->len--;
     830             :                         }
     831        1576 :                         len += b->len;
     832             :                 } else {
     833             :                         /* this block will not be used, delete all constants there */
     834         119 :                         zend_op *op = op_array->opcodes + b->start;
     835         119 :                         zend_op *end = op + b->len;
     836         247 :                         for (; op < end; op++) {
     837         128 :                                 if (ZEND_OP1_TYPE(op) == IS_CONST) {
     838         160 :                                         literal_dtor(&ZEND_OP1_LITERAL(op));
     839             :                                 }
     840         128 :                                 if (ZEND_OP2_TYPE(op) == IS_CONST) {
     841           0 :                                         literal_dtor(&ZEND_OP2_LITERAL(op));
     842             :                                 }
     843             :                         }
     844             :                 }
     845             :         }
     846             : 
     847         726 :         new_opcodes = emalloc(len * sizeof(zend_op));
     848         726 :         opline = new_opcodes;
     849             : 
     850             :         /* Copy code of reachable blocks into a single buffer */
     851        3042 :         for (b = blocks; b < end; b++) {
     852        2316 :                 if (b->flags & ZEND_BB_REACHABLE) {
     853        1578 :                         memcpy(opline, op_array->opcodes + b->start, b->len * sizeof(zend_op));
     854        1578 :                         b->start = opline - new_opcodes;
     855        1578 :                         opline += b->len;
     856             :                 }
     857             :         }
     858             : 
     859             :         /* adjust jump targets */
     860         726 :         efree(op_array->opcodes);
     861         726 :         op_array->opcodes = new_opcodes;
     862         726 :         op_array->last = len;
     863             : 
     864        3042 :         for (b = blocks; b < end; b++) {
     865        2316 :                 if (!(b->flags & ZEND_BB_REACHABLE) || b->len == 0) {
     866         740 :                         continue;
     867             :                 }
     868        1576 :                 opline = op_array->opcodes + b->start + b->len - 1;
     869        1576 :                 switch (opline->opcode) {
     870             :                         case ZEND_FAST_CALL:
     871             :                         case ZEND_JMP:
     872          47 :                                 ZEND_SET_OP_JMP_ADDR(opline, opline->op1, new_opcodes + blocks[b->successors[0]].start);
     873          47 :                                 break;
     874             :                         case ZEND_JMPZNZ:
     875           7 :                                 opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[1]].start);
     876             :                                 /* break missing intentionally */
     877             :                         case ZEND_JMPZ:
     878             :                         case ZEND_JMPNZ:
     879             :                         case ZEND_JMPZ_EX:
     880             :                         case ZEND_JMPNZ_EX:
     881             :                         case ZEND_FE_RESET_R:
     882             :                         case ZEND_FE_RESET_RW:
     883             :                         case ZEND_JMP_SET:
     884             :                         case ZEND_COALESCE:
     885             :                         case ZEND_ASSERT_CHECK:
     886         268 :                                 ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
     887         268 :                                 break;
     888             :                         case ZEND_CATCH:
     889           0 :                                 if (!opline->result.var) {
     890           0 :                                         opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[0]].start);
     891             :                                 }
     892           0 :                                 break;
     893             :                         case ZEND_DECLARE_ANON_CLASS:
     894             :                         case ZEND_DECLARE_ANON_INHERITED_CLASS:
     895             :                         case ZEND_FE_FETCH_R:
     896             :                         case ZEND_FE_FETCH_RW:
     897           6 :                                 opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[0]].start);
     898             :                                 break;
     899             :                 }
     900             :         }
     901             : 
     902             :         /* adjust exception jump targets & remove unused try_catch_array entries */
     903         726 :         if (op_array->last_try_catch) {
     904             :                 int i, j;
     905             :                 uint32_t *map;
     906             :                 ALLOCA_FLAG(use_heap);
     907             : 
     908          14 :                 map = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last_try_catch, use_heap);
     909          33 :                 for (i = 0, j = 0; i< op_array->last_try_catch; i++) {
     910          19 :                         if (blocks[cfg->map[op_array->try_catch_array[i].try_op]].flags & ZEND_BB_REACHABLE) {
     911          17 :                                 map[i] = j;
     912          17 :                                 op_array->try_catch_array[j].try_op = blocks[cfg->map[op_array->try_catch_array[i].try_op]].start;
     913          17 :                                 if (op_array->try_catch_array[i].catch_op) {
     914          16 :                                         op_array->try_catch_array[j].catch_op = blocks[cfg->map[op_array->try_catch_array[i].catch_op]].start;
     915             :                                 } else {
     916           1 :                                         op_array->try_catch_array[j].catch_op =  0;
     917             :                                 }
     918          17 :                                 if (op_array->try_catch_array[i].finally_op) {
     919           1 :                                         op_array->try_catch_array[j].finally_op = blocks[cfg->map[op_array->try_catch_array[i].finally_op]].start;
     920             :                                 } else {
     921          16 :                                         op_array->try_catch_array[j].finally_op =  0;
     922             :                                 }
     923          17 :                                 if (!op_array->try_catch_array[i].finally_end) {
     924          16 :                                         op_array->try_catch_array[j].finally_end = 0;
     925             :                                 } else {
     926           1 :                                         op_array->try_catch_array[j].finally_end = blocks[cfg->map[op_array->try_catch_array[i].finally_end]].start;
     927             :                                 }
     928          17 :                                 j++;
     929             :                         }
     930             :                 }
     931          14 :                 if (i != j) {
     932           2 :                         op_array->last_try_catch = j;
     933           2 :                         if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
     934           0 :                                 zend_op *opline = new_opcodes;
     935           0 :                                 zend_op *end = opline + len;
     936           0 :                                 while (opline < end) {
     937           0 :                                         if (opline->opcode == ZEND_FAST_RET &&
     938           0 :                                             opline->op2.num != (uint32_t)-1 &&
     939           0 :                                             opline->op2.num < (uint32_t)j) {
     940           0 :                                                 opline->op2.num = map[opline->op2.num];
     941             :                                         }
     942           0 :                                         opline++;
     943             :                                 }
     944             :                         }
     945             :                 }
     946          14 :                 free_alloca(map, use_heap);
     947             :         }
     948             : 
     949             :         /* adjust loop jump targets & remove unused live range entries */
     950         726 :         if (op_array->last_live_range) {
     951             :                 int i, j;
     952             :                 uint32_t *map;
     953             :                 ALLOCA_FLAG(use_heap);
     954             : 
     955          92 :                 map = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last_live_range, use_heap);
     956             : 
     957         312 :                 for (i = 0, j = 0; i < op_array->last_live_range; i++) {
     958         220 :                         if (op_array->live_range[i].var == (uint32_t)-1) {
     959             :                                 /* this live range already removed */
     960           0 :                                 continue;
     961             :                         }
     962         220 :                         if (!(blocks[cfg->map[op_array->live_range[i].start]].flags & ZEND_BB_REACHABLE)) {
     963             :                                 ZEND_ASSERT(!(blocks[cfg->map[op_array->live_range[i].end]].flags & ZEND_BB_REACHABLE));
     964             :                         } else {
     965         205 :                                 uint32_t start_op = blocks[cfg->map[op_array->live_range[i].start]].start;
     966         205 :                                 uint32_t end_op = blocks[cfg->map[op_array->live_range[i].end]].start;
     967             : 
     968         205 :                                 if (start_op == end_op) {
     969             :                                         /* skip empty live range */
     970           0 :                                         continue;
     971             :                                 }
     972         205 :                                 op_array->live_range[i].start = start_op;
     973         205 :                                 op_array->live_range[i].end = end_op;
     974         205 :                                 map[i] = j;
     975         205 :                                 if (i != j) {
     976          45 :                                         op_array->live_range[j]  = op_array->live_range[i];
     977             :                                 }
     978         205 :                                 j++;
     979             :                         }
     980             :                 }
     981             : 
     982          92 :                 if (i != j) {
     983          15 :                         if ((op_array->last_live_range = j)) {
     984          15 :                                 zend_op *opline = new_opcodes;
     985          15 :                                 zend_op *end = opline + len;
     986         645 :                                 while (opline != end) {
     987         615 :                                         if ((opline->opcode == ZEND_FREE || opline->opcode == ZEND_FE_FREE) &&
     988           0 :                                                         opline->extended_value == ZEND_FREE_ON_RETURN) {
     989             :                                                 ZEND_ASSERT(opline->op2.num < (uint32_t) i);
     990           0 :                                                 opline->op2.num = map[opline->op2.num];
     991             :                                         }
     992         615 :                                         opline++;
     993             :                                 }
     994             :                         } else {
     995           0 :                                 efree(op_array->live_range);
     996           0 :                                 op_array->live_range = NULL;
     997             :                         }
     998             :                 }
     999          92 :                 free_alloca(map, use_heap);
    1000             :         }
    1001             : 
    1002             :         /* adjust early binding list */
    1003         726 :         if (op_array->early_binding != (uint32_t)-1) {
    1004           5 :                 uint32_t *opline_num = &op_array->early_binding;
    1005             :                 zend_op *end;
    1006             : 
    1007           5 :                 opline = op_array->opcodes;
    1008           5 :                 end = opline + op_array->last;
    1009         250 :                 while (opline < end) {
    1010         240 :                         if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
    1011           5 :                                 *opline_num = opline - op_array->opcodes;
    1012           5 :                                 opline_num = &ZEND_RESULT(opline).opline_num;
    1013             :                         }
    1014         240 :                         ++opline;
    1015             :                 }
    1016           5 :                 *opline_num = -1;
    1017             :         }
    1018             : 
    1019             :         /* rebuild map (just for printing) */
    1020         726 :         memset(cfg->map, -1, sizeof(int) * op_array->last);
    1021        3042 :         for (n = 0; n < cfg->blocks_count; n++) {
    1022        2316 :                 if (cfg->blocks[n].flags & ZEND_BB_REACHABLE) {
    1023        1578 :                         cfg->map[cfg->blocks[n].start] = n;
    1024             :                 }
    1025             :         }
    1026         726 : }
    1027             : 
    1028        5154 : static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_array, zend_cfg *cfg, zend_uchar *same_t)
    1029             : {
    1030             :         /* last_op is the last opcode of the current block */
    1031        5154 :         zend_basic_block *blocks = cfg->blocks;
    1032             :         zend_op *last_op;
    1033             : 
    1034        5154 :         if (block->len == 0) {
    1035           6 :                 return;
    1036             :         }
    1037             : 
    1038        5148 :         last_op = op_array->opcodes + block->start + block->len - 1;
    1039        5148 :         switch (last_op->opcode) {
    1040             :                 case ZEND_JMP:
    1041             :                         {
    1042         409 :                                 zend_basic_block *target_block = blocks + block->successors[0];
    1043         409 :                                 zend_op *target = op_array->opcodes + target_block->start;
    1044         409 :                                 int next = (block - blocks) + 1;
    1045             : 
    1046        1170 :                                 while (next < cfg->blocks_count && !(blocks[next].flags & ZEND_BB_REACHABLE)) {
    1047             :                                         /* find used one */
    1048         352 :                                         next++;
    1049             :                                 }
    1050             : 
    1051             :                                 /* JMP(next) -> NOP */
    1052         409 :                                 if (block->successors[0] == next) {
    1053         247 :                                         MAKE_NOP(last_op);
    1054         247 :                                         block->len--;
    1055         247 :                                         break;
    1056             :                                 }
    1057             : 
    1058         162 :                                 if (target->opcode == ZEND_JMP &&
    1059           0 :                                         block->successors[0] != target_block->successors[0] &&
    1060           0 :                                         !(target_block->flags & ZEND_BB_PROTECTED)) {
    1061             :                                         /* JMP L, L: JMP L1 -> JMP L1 */
    1062           0 :                                         *last_op = *target;
    1063             :                                         DEL_SOURCE(block, block->successors[0]);
    1064           0 :                                         block->successors[0] = target_block->successors[0];
    1065             :                                         ADD_SOURCE(block, block->successors[0]);
    1066         162 :                                 } else if (target->opcode == ZEND_JMPZNZ &&
    1067           0 :                                            !(target_block->flags & ZEND_BB_PROTECTED)) {
    1068             :                                         /* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ L1,L2 */
    1069           0 :                                         *last_op = *target;
    1070           0 :                                         if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
    1071           0 :                                                 zval zv = ZEND_OP1_LITERAL(last_op);
    1072             :                                                 zval_copy_ctor(&zv);
    1073           0 :                                                 last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
    1074             :                                         }
    1075             :                                         DEL_SOURCE(block, block->successors[0]);
    1076           0 :                                         block->successors[0] = target_block->successors[0];
    1077           0 :                                         block->successors[1] = target_block->successors[1];
    1078             :                                         ADD_SOURCE(block, block->successors[0]);
    1079             :                                         ADD_SOURCE(block, block->successors[1]);
    1080         477 :                                 } else if ((target->opcode == ZEND_RETURN ||
    1081         153 :                                             target->opcode == ZEND_RETURN_BY_REF ||
    1082         153 :                                             target->opcode == ZEND_EXIT) &&
    1083           9 :                                            !(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
    1084             :                                         /* JMP L, L: RETURN to immediate RETURN */
    1085           9 :                                         *last_op = *target;
    1086           9 :                                         if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
    1087           9 :                                                 zval zv = ZEND_OP1_LITERAL(last_op);
    1088             :                                                 zval_copy_ctor(&zv);
    1089           9 :                                                 last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
    1090             :                                         }
    1091             :                                         DEL_SOURCE(block, block->successors[0]);
    1092           9 :                                         block->successors[0] = -1;
    1093             : #if 0
    1094             :                                 /* Temporarily disabled - see bug #0025274 */
    1095             :                                 } else if (0&& block->op1_to != block &&
    1096             :                                    block->op1_to != blocks &&
    1097             :                                                    op_array->last_try_catch == 0 &&
    1098             :                                            target->opcode != ZEND_FREE) {
    1099             :                                     /* Block Reordering (saves one JMP on each "for" loop iteration)
    1100             :                                      * It is disabled for some cases (ZEND_FREE)
    1101             :                                      * which may break register allocation.
    1102             :                      */
    1103             :                                         zend_bool can_reorder = 0;
    1104             :                                         zend_block_source *cs = block->op1_to->sources;
    1105             : 
    1106             :                                         /* the "target" block doesn't had any followed block */
    1107             :                                         while(cs) {
    1108             :                                                 if (cs->from->follow_to == block->op1_to) {
    1109             :                                                         can_reorder = 0;
    1110             :                                                         break;
    1111             :                                                 }
    1112             :                                                 cs = cs->next;
    1113             :                                         }
    1114             :                                         if (can_reorder) {
    1115             :                                                 next = block->op1_to;
    1116             :                                                 /* the "target" block is not followed by current "block" */
    1117             :                                                 while (next->follow_to != NULL) {
    1118             :                                                         if (next->follow_to == block) {
    1119             :                                                                 can_reorder = 0;
    1120             :                                                                 break;
    1121             :                                                         }
    1122             :                                                         next = next->follow_to;
    1123             :                                                 }
    1124             :                                                 if (can_reorder) {
    1125             :                                                         zend_basic_block *prev = blocks;
    1126             : 
    1127             :                                                         while (prev->next != block->op1_to) {
    1128             :                                                                 prev = prev->next;
    1129             :                                                         }
    1130             :                                                         prev->next = next->next;
    1131             :                                                         next->next = block->next;
    1132             :                                                         block->next = block->op1_to;
    1133             : 
    1134             :                                                         block->follow_to = block->op1_to;
    1135             :                                                         block->op1_to = NULL;
    1136             :                                                         MAKE_NOP(last_op);
    1137             :                                                         block->len--;
    1138             :                                                         if(block->len == 0) {
    1139             :                                                                 /* this block is nothing but NOP now */
    1140             :                                                                 delete_code_block(block, ctx);
    1141             :                                                         }
    1142             :                                                         break;
    1143             :                                                 }
    1144             :                                         }
    1145             : #endif
    1146             :                                 }
    1147             :                         }
    1148         162 :                         break;
    1149             : 
    1150             :                 case ZEND_JMPZ:
    1151             :                 case ZEND_JMPNZ:
    1152             :                         /* constant conditional JMPs */
    1153         800 :                         if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
    1154          24 :                                 int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
    1155             : 
    1156          24 :                                 if (last_op->opcode == ZEND_JMPZ) {
    1157          17 :                                         should_jmp = !should_jmp;
    1158             :                                 }
    1159          48 :                                 literal_dtor(&ZEND_OP1_LITERAL(last_op));
    1160          24 :                                 ZEND_OP1_TYPE(last_op) = IS_UNUSED;
    1161          24 :                                 if (should_jmp) {
    1162             :                                         /* JMPNZ(true) -> JMP */
    1163          24 :                                         last_op->opcode = ZEND_JMP;
    1164             :                                         DEL_SOURCE(block, block->successors[1]);
    1165          24 :                                         block->successors[1] = -1;
    1166             :                                 } else {
    1167             :                                         /* JMPNZ(false) -> NOP */
    1168           0 :                                         MAKE_NOP(last_op);
    1169             :                                         DEL_SOURCE(block, block->successors[0]);
    1170           0 :                                         block->successors[0] = block->successors[1];
    1171           0 :                                         block->successors[1] = -1;
    1172             :                                 }
    1173          24 :                                 break;
    1174             :                         }
    1175             : 
    1176         776 :                         if (block->successors[0] == block->successors[1]) {
    1177             :                                 /* L: JMP[N]Z(X, L+1) -> NOP or FREE(X) */
    1178             : 
    1179           5 :                                 if (last_op->op1_type == IS_CV) {
    1180           1 :                                         last_op->opcode = ZEND_CHECK_VAR;
    1181           1 :                                         last_op->op2.num = 0;
    1182           4 :                                 } else if (last_op->op1_type & (IS_VAR|IS_TMP_VAR)) {
    1183           4 :                                         last_op->opcode = ZEND_FREE;
    1184           4 :                                         last_op->op2.num = 0;
    1185             :                                 } else {
    1186           0 :                                         MAKE_NOP(last_op);
    1187             :                                 }
    1188           5 :                                 block->successors[1] = -1;
    1189           5 :                                 break;
    1190             :                         }
    1191             : 
    1192             :                         if (1) {
    1193         771 :                                 zend_uchar same_type = ZEND_OP1_TYPE(last_op);
    1194         771 :                                 uint32_t same_var = VAR_NUM_EX(last_op->op1);
    1195             :                                 zend_op *target;
    1196             :                                 zend_op *target_end;
    1197         771 :                                 zend_basic_block *target_block = blocks + block->successors[0];
    1198             : 
    1199             : next_target:
    1200         771 :                                 target = op_array->opcodes + target_block->start;
    1201         771 :                                 target_end = target + target_block->len;
    1202        1542 :                                 while (target < target_end && target->opcode == ZEND_NOP) {
    1203           0 :                                         target++;
    1204             :                                 }
    1205             : 
    1206             :                                 /* next block is only NOP's */
    1207         771 :                                 if (target == target_end) {
    1208           0 :                                         target_block = blocks + target_block->successors[0];
    1209           0 :                                         goto next_target;
    1210         879 :                                 } else if (target->opcode == INV_COND(last_op->opcode) &&
    1211             :                                         /* JMPZ(X, L), L: JMPNZ(X, L2) -> JMPZ(X, L+1) */
    1212          54 :                                    (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
    1213          54 :                                    same_type == ZEND_OP1_TYPE(target) &&
    1214           0 :                                    same_var == VAR_NUM_EX(target->op1) &&
    1215           0 :                                    !(target_block->flags & ZEND_BB_PROTECTED)
    1216             :                                    ) {
    1217             :                                         DEL_SOURCE(block, block->successors[0]);
    1218           0 :                                         block->successors[0] = target_block->successors[1];
    1219             :                                         ADD_SOURCE(block, block->successors[0]);
    1220         771 :                                 } else if (target->opcode == INV_COND_EX(last_op->opcode) &&
    1221           0 :                                                         (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
    1222           0 :                                                 same_type == ZEND_OP1_TYPE(target) &&
    1223           0 :                                                 same_var == VAR_NUM_EX(target->op1) &&
    1224           0 :                                                         !(target_block->flags & ZEND_BB_PROTECTED)) {
    1225             :                                         /* JMPZ(X, L), L: T = JMPNZ_EX(X, L2) -> T = JMPZ_EX(X, L+1) */
    1226           0 :                                         last_op->opcode += 3;
    1227           0 :                                         COPY_NODE(last_op->result, target->result);
    1228             :                                         DEL_SOURCE(block, block->successors[0]);
    1229           0 :                                         block->successors[0] = target_block->successors[1];
    1230             :                                         ADD_SOURCE(block, block->successors[0]);
    1231         823 :                                 } else if (target->opcode == last_op->opcode &&
    1232          14 :                                                    (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
    1233          14 :                                                    same_type == ZEND_OP1_TYPE(target) &&
    1234          14 :                                                    same_var == VAR_NUM_EX(target->op1) &&
    1235           5 :                                                    !(target_block->flags & ZEND_BB_PROTECTED)) {
    1236             :                                         /* JMPZ(X, L), L: JMPZ(X, L2) -> JMPZ(X, L2) */
    1237             :                                         DEL_SOURCE(block, block->successors[0]);
    1238           5 :                                         block->successors[0] = target_block->successors[0];
    1239             :                                         ADD_SOURCE(block, block->successors[0]);
    1240         798 :                                 } else if (target->opcode == ZEND_JMP &&
    1241          16 :                                            !(target_block->flags & ZEND_BB_PROTECTED)) {
    1242             :                                         /* JMPZ(X, L), L: JMP(L2) -> JMPZ(X, L2) */
    1243             :                                         DEL_SOURCE(block, block->successors[0]);
    1244          16 :                                         block->successors[0] = target_block->successors[0];
    1245             :                                         ADD_SOURCE(block, block->successors[0]);
    1246         750 :                                 } else if (target->opcode == ZEND_JMPZNZ &&
    1247           0 :                                            (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
    1248           0 :                                            same_type == ZEND_OP1_TYPE(target) &&
    1249           0 :                                            same_var == VAR_NUM_EX(target->op1) &&
    1250           0 :                                            !(target_block->flags & ZEND_BB_PROTECTED)) {
    1251             :                                         /* JMPZ(X, L), L: JMPZNZ(X, L2, L3) -> JMPZ(X, L2) */
    1252             :                                         DEL_SOURCE(block, block->successors[0]);
    1253           0 :                                         if (last_op->opcode == ZEND_JMPZ) {
    1254           0 :                                                 block->successors[0] = target_block->successors[0];
    1255             :                                         } else {
    1256           0 :                                                 block->successors[0] = target_block->successors[1];
    1257             :                                         }
    1258             :                                         ADD_SOURCE(block, block->successors[0]);
    1259             :                                 }
    1260             :                         }
    1261             : 
    1262         771 :                         if (last_op->opcode == ZEND_JMPZ || last_op->opcode == ZEND_JMPNZ) {
    1263             :                                 zend_op *target;
    1264             :                                 zend_op *target_end;
    1265             :                                 zend_basic_block *target_block;
    1266             : 
    1267             :                                 while (1) {
    1268         771 :                                         target_block = blocks + block->successors[1];
    1269         771 :                                         target = op_array->opcodes + target_block->start;
    1270         771 :                                         target_end = op_array->opcodes + target_block->start + 1;
    1271        1542 :                                         while (target < target_end && target->opcode == ZEND_NOP) {
    1272           0 :                                                 target++;
    1273             :                                         }
    1274             : 
    1275             :                                         /* next block is only NOP's */
    1276         771 :                                         if (target == target_end && !(target_block->flags & ZEND_BB_PROTECTED)) {
    1277             :                                                 DEL_SOURCE(block, block->successors[1]);
    1278           0 :                                                 block->successors[1] = target_block->successors[0];
    1279             :                                                 ADD_SOURCE(block, block->successors[1]);
    1280             :                                         } else {
    1281             :                                                 break;
    1282             :                                         }
    1283           0 :                                 }
    1284             :                                 /* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
    1285         774 :                                 if (target->opcode == ZEND_JMP &&
    1286           3 :                                         !(target_block->flags & ZEND_BB_PROTECTED)) {
    1287             :                                         DEL_SOURCE(block, block->successors[1]);
    1288           3 :                                         if (last_op->opcode == ZEND_JMPZ) {
    1289           3 :                                                 block->successors[1] = target_block->successors[0];
    1290             :                                                 ADD_SOURCE(block, block->successors[1]);
    1291             :                                         } else {
    1292           0 :                                                 block->successors[1] = block->successors[0];
    1293           0 :                                                 block->successors[0] = target_block->successors[0];
    1294             :                                                 ADD_SOURCE(block, block->successors[0]);
    1295             :                                         }
    1296           3 :                                         last_op->opcode = ZEND_JMPZNZ;
    1297             :                                 }
    1298             :                         }
    1299         771 :                         break;
    1300             : 
    1301             :                 case ZEND_JMPNZ_EX:
    1302             :                 case ZEND_JMPZ_EX:
    1303             :                         /* constant conditional JMPs */
    1304          16 :                         if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
    1305           0 :                                 int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
    1306             : 
    1307           0 :                                 if (last_op->opcode == ZEND_JMPZ_EX) {
    1308           0 :                                         should_jmp = !should_jmp;
    1309             :                                 }
    1310           0 :                                 if (!should_jmp) {
    1311             :                                         /* T = JMPZ_EX(true,L)   -> T = QM_ASSIGN(true)
    1312             :                                          * T = JMPNZ_EX(false,L) -> T = QM_ASSIGN(false)
    1313             :                                          */
    1314           0 :                                         last_op->opcode = ZEND_QM_ASSIGN;
    1315           0 :                                         SET_UNUSED(last_op->op2);
    1316             :                                         DEL_SOURCE(block, block->successors[0]);
    1317           0 :                                         block->successors[0] = block->successors[1];
    1318           0 :                                         block->successors[1] = -1;
    1319             :                                 }
    1320           0 :                                 break;
    1321             :                         }
    1322             : 
    1323             :                         if (1) {
    1324             :                                 zend_op *target, *target_end;
    1325             :                                 zend_basic_block *target_block;
    1326          16 :                                 int var_num = op_array->last_var + op_array->T;
    1327             : 
    1328          16 :                                 if (var_num <= 0) {
    1329           0 :                                         return;
    1330             :                                 }
    1331          16 :                                 memset(same_t, 0, var_num);
    1332          16 :                                 same_t[VAR_NUM_EX(last_op->op1)] |= ZEND_OP1_TYPE(last_op);
    1333          16 :                                 same_t[VAR_NUM_EX(last_op->result)] |= ZEND_RESULT_TYPE(last_op);
    1334          16 :                                 target_block = blocks + block->successors[0];
    1335             : next_target_ex:
    1336          16 :                                 target = op_array->opcodes + target_block->start;
    1337          16 :                                 target_end = target + target_block->len;
    1338          32 :                                 while (target < target_end && target->opcode == ZEND_NOP) {
    1339           0 :                                         target++;
    1340             :                                 }
    1341             :                                 /* next block is only NOP's */
    1342          16 :                                 if (target == target_end) {
    1343           0 :                                         target_block = blocks + target_block->successors[0];
    1344           0 :                                         goto next_target_ex;
    1345          16 :                                 } else if (target->opcode == last_op->opcode-3 &&
    1346           0 :                                                    (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
    1347           0 :                                                    (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
    1348           0 :                                                    !(target_block->flags & ZEND_BB_PROTECTED)) {
    1349             :                                         /* T = JMPZ_EX(X, L1), L1: JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
    1350             :                                         DEL_SOURCE(block, block->successors[0]);
    1351           0 :                                         block->successors[0] = target_block->successors[0];
    1352             :                                         ADD_SOURCE(block, block->successors[0]);
    1353          32 :                                 } else if (target->opcode == INV_EX_COND(last_op->opcode) &&
    1354           4 :                                                    (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
    1355           4 :                                                    (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
    1356           4 :                                                    !(target_block->flags & ZEND_BB_PROTECTED)) {
    1357             :                                         /* T = JMPZ_EX(X, L1), L1: JMPNZ({X|T1}, L2) -> T = JMPZ_EX(X, L1+1) */
    1358             :                                         DEL_SOURCE(block, block->successors[0]);
    1359           4 :                                         block->successors[0] = target_block->successors[1];
    1360             :                                         ADD_SOURCE(block, block->successors[0]);
    1361          12 :                                 } else if (target->opcode == INV_EX_COND_EX(last_op->opcode) &&
    1362           0 :                                                (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
    1363           0 :                                                    (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
    1364           0 :                                                    (same_t[VAR_NUM_EX(target->result)] & ZEND_RESULT_TYPE(target)) != 0 &&
    1365           0 :                                                    !(target_block->flags & ZEND_BB_PROTECTED)) {
    1366             :                                         /* T = JMPZ_EX(X, L1), L1: T = JMPNZ_EX(T, L2) -> T = JMPZ_EX(X, L1+1) */
    1367             :                                         DEL_SOURCE(block, block->successors[0]);
    1368           0 :                                         block->successors[0] = target_block->successors[1];
    1369             :                                         ADD_SOURCE(block, block->successors[0]);
    1370          12 :                                 } else if (target->opcode == last_op->opcode &&
    1371           0 :                                                    (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
    1372           0 :                                                    (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
    1373           0 :                                                    (same_t[VAR_NUM_EX(target->result)] & ZEND_RESULT_TYPE(target)) != 0 &&
    1374           0 :                                                    !(target_block->flags & ZEND_BB_PROTECTED)) {
    1375             :                                         /* T = JMPZ_EX(X, L1), L1: T = JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
    1376             :                                         DEL_SOURCE(block, block->successors[0]);
    1377           0 :                                         block->successors[0] = target_block->successors[0];
    1378             :                                         ADD_SOURCE(block, block->successors[0]);
    1379          12 :                                 } else if (target->opcode == ZEND_JMP &&
    1380           0 :                                                    !(target_block->flags & ZEND_BB_PROTECTED)) {
    1381             :                                         /* T = JMPZ_EX(X, L), L: JMP(L2) -> T = JMPZ(X, L2) */
    1382             :                                         DEL_SOURCE(block, block->successors[0]);
    1383           0 :                                         block->successors[0] = target_block->successors[0];
    1384             :                                         ADD_SOURCE(block, block->successors[0]);
    1385          21 :                                 } else if (target->opcode == ZEND_JMPZNZ &&
    1386           3 :                                                    (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
    1387           3 :                                                    (same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
    1388           3 :                                                    !(target_block->flags & ZEND_BB_PROTECTED)) {
    1389             :                                         /* T = JMPZ_EX(X, L), L: JMPZNZ({X|T}, L2, L3) -> T = JMPZ_EX(X, L2) */
    1390             :                                         DEL_SOURCE(block, block->successors[0]);
    1391           3 :                                         if (last_op->opcode == ZEND_JMPZ_EX) {
    1392           3 :                                                 block->successors[0] = target_block->successors[0];
    1393             :                                         } else {
    1394           0 :                                                 block->successors[0] = target_block->successors[1];
    1395             :                                         }
    1396             :                                         ADD_SOURCE(block, block->successors[0]);
    1397             :                                 }
    1398             :                         }
    1399          16 :                         break;
    1400             : 
    1401             :                 case ZEND_JMPZNZ: {
    1402          29 :                         int next = (block - blocks) + 1;
    1403             : 
    1404         108 :                         while (next < cfg->blocks_count && !(blocks[next].flags & ZEND_BB_REACHABLE)) {
    1405             :                                 /* find first accessed one */
    1406          50 :                                 next++;
    1407             :                         }
    1408             : 
    1409          29 :                         if (ZEND_OP1_TYPE(last_op) == IS_CONST) {
    1410           0 :                                 if (!zend_is_true(&ZEND_OP1_LITERAL(last_op))) {
    1411             :                                         /* JMPZNZ(false,L1,L2) -> JMP(L1) */
    1412           0 :                                         literal_dtor(&ZEND_OP1_LITERAL(last_op));
    1413           0 :                                         last_op->opcode = ZEND_JMP;
    1414           0 :                                         SET_UNUSED(last_op->op1);
    1415           0 :                                         SET_UNUSED(last_op->op2);
    1416             :                                         DEL_SOURCE(block, block->successors[1]);
    1417           0 :                                         block->successors[1] = -1;
    1418             :                                 } else {
    1419             :                                         /* JMPZNZ(true,L1,L2) -> JMP(L2) */
    1420           0 :                                         literal_dtor(&ZEND_OP1_LITERAL(last_op));
    1421           0 :                                         last_op->opcode = ZEND_JMP;
    1422           0 :                                         SET_UNUSED(last_op->op1);
    1423           0 :                                         SET_UNUSED(last_op->op2);
    1424             :                                         DEL_SOURCE(block, block->successors[0]);
    1425           0 :                                         block->successors[0] = block->successors[1];
    1426           0 :                                         block->successors[1] = -1;
    1427             :                                 }
    1428          29 :                         } else if (block->successors[0] == block->successors[1]) {
    1429             :                                 /* both goto the same one - it's JMP */
    1430           5 :                                 if (!(last_op->op1_type & (IS_VAR|IS_TMP_VAR))) {
    1431             :                                         /* JMPZNZ(?,L,L) -> JMP(L) */
    1432           0 :                                         last_op->opcode = ZEND_JMP;
    1433           0 :                                         SET_UNUSED(last_op->op1);
    1434           0 :                                         SET_UNUSED(last_op->op2);
    1435           0 :                                         block->successors[1] = -1;
    1436             :                                 }
    1437          24 :                         } else if (block->successors[0] == next) {
    1438             :                                 /* jumping to next on Z - can follow to it and jump only on NZ */
    1439             :                                 /* JMPZNZ(X,L1,L2) L1: -> JMPNZ(X,L2) */
    1440           3 :                                 last_op->opcode = ZEND_JMPNZ;
    1441           3 :                                 block->successors[0] = block->successors[1];
    1442           3 :                                 block->successors[1] = next;
    1443             :                                 /* no need to add source */
    1444          21 :                         } else if (block->successors[1] == next) {
    1445             :                                 /* jumping to next on NZ - can follow to it and jump only on Z */
    1446             :                                 /* JMPZNZ(X,L1,L2) L2: -> JMPZ(X,L1) */
    1447           9 :                                 last_op->opcode = ZEND_JMPZ;
    1448             :                                 /* no need to add source */
    1449             :                         }
    1450             : 
    1451          29 :                         if (last_op->opcode == ZEND_JMPZNZ) {
    1452          17 :                                 zend_uchar same_type = ZEND_OP1_TYPE(last_op);
    1453          17 :                                 zend_uchar same_var = VAR_NUM_EX(last_op->op1);
    1454             :                                 zend_op *target;
    1455             :                                 zend_op *target_end;
    1456          17 :                                 zend_basic_block *target_block = blocks + block->successors[0];
    1457             : 
    1458             : next_target_znz:
    1459          17 :                                 target = op_array->opcodes + target_block->start;
    1460          17 :                                 target_end = target + target_block->len;
    1461          34 :                                 while (target < target_end && target->opcode == ZEND_NOP) {
    1462           0 :                                         target++;
    1463             :                                 }
    1464             :                                 /* next block is only NOP's */
    1465          17 :                                 if (target == target_end) {
    1466           0 :                                         target_block = blocks + target_block->successors[0];
    1467           0 :                                         goto next_target_znz;
    1468          17 :                                 } else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
    1469           0 :                                                    (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
    1470           0 :                                                    same_type == ZEND_OP1_TYPE(target) &&
    1471           0 :                                                    same_var == VAR_NUM_EX(target->op1) &&
    1472           0 :                                                    !(target_block->flags & ZEND_BB_PROTECTED)) {
    1473             :                                     /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
    1474             :                                         DEL_SOURCE(block, block->successors[0]);
    1475           0 :                                         block->successors[0] = target_block->successors[0];
    1476             :                                         ADD_SOURCE(block, block->successors[0]);
    1477          17 :                                 } else if (target->opcode == ZEND_JMPNZ &&
    1478           0 :                                                    (ZEND_OP1_TYPE(target) & (IS_TMP_VAR|IS_CV)) &&
    1479           0 :                                                    same_type == ZEND_OP1_TYPE(target) &&
    1480           0 :                                                    same_var == VAR_NUM_EX(target->op1) &&
    1481           0 :                                                    !(target_block->flags & ZEND_BB_PROTECTED)) {
    1482             :                     /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
    1483             :                                         DEL_SOURCE(block, block->successors[0]);
    1484           0 :                                         block->successors[0] = target_block->successors[1];
    1485             :                                         ADD_SOURCE(block, block->successors[0]);
    1486          17 :                                 } else if (target->opcode == ZEND_JMP &&
    1487           0 :                                                !(target_block->flags & ZEND_BB_PROTECTED)) {
    1488             :                     /* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
    1489             :                                         DEL_SOURCE(block, block->successors[0]);
    1490           0 :                                         block->successors[0] = target_block->successors[0];
    1491             :                                         ADD_SOURCE(block, block->successors[0]);
    1492             :                                 }
    1493             :                         }
    1494             :                         break;
    1495             :                 }
    1496             :         }
    1497             : }
    1498             : 
    1499             : /* Global data dependencies */
    1500             : 
    1501             : /* Find a set of variables which are used outside of the block where they are
    1502             :  * defined. We won't apply some optimization patterns for such variables. */
    1503        2904 : static void zend_t_usage(zend_cfg *cfg, zend_op_array *op_array, zend_bitset used_ext, zend_optimizer_ctx *ctx)
    1504             : {
    1505             :         int n;
    1506             :         zend_basic_block *block, *next_block;
    1507             :         uint32_t var_num;
    1508             :         uint32_t bitset_len;
    1509             :         zend_bitset usage;
    1510             :         zend_bitset defined_here;
    1511             :         void *checkpoint;
    1512             :         zend_op *opline, *end;
    1513             : 
    1514             : 
    1515        2904 :         if (op_array->T == 0) {
    1516             :                 /* shortcut - if no Ts, nothing to do */
    1517         192 :                 return;
    1518             :         }
    1519             : 
    1520        5424 :         checkpoint = zend_arena_checkpoint(ctx->arena);
    1521        2712 :         bitset_len = zend_bitset_len(op_array->last_var + op_array->T);
    1522        5424 :         defined_here = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
    1523             : 
    1524        2712 :         zend_bitset_clear(defined_here, bitset_len);
    1525        8996 :         for (n = 1; n < cfg->blocks_count; n++) {
    1526        6284 :                 block = cfg->blocks + n;
    1527             : 
    1528        6284 :                 if (!(block->flags & ZEND_BB_REACHABLE)) {
    1529        2456 :                         continue;
    1530             :                 }
    1531             : 
    1532        3828 :                 opline = op_array->opcodes + block->start;
    1533        3828 :                 end = opline + block->len;
    1534        6708 :                 if (!(block->flags & ZEND_BB_FOLLOW) ||
    1535        2880 :                     (block->flags & ZEND_BB_TARGET)) {
    1536             :                         /* Skip continuation of "extended" BB */
    1537        1388 :                         zend_bitset_clear(defined_here, bitset_len);
    1538             :                 }
    1539             : 
    1540       22140 :                 while (opline<end) {
    1541       14484 :                         if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
    1542        3745 :                                 var_num = VAR_NUM(opline->op1.var);
    1543        3745 :                                 if (!zend_bitset_in(defined_here, var_num)) {
    1544         308 :                                         zend_bitset_incl(used_ext, var_num);
    1545             :                                 }
    1546             :                         }
    1547       14484 :                         if (opline->op2_type == IS_VAR) {
    1548         649 :                                 var_num = VAR_NUM(opline->op2.var);
    1549        1298 :                                 if (opline->opcode == ZEND_FE_FETCH_R ||
    1550         649 :                                     opline->opcode == ZEND_FE_FETCH_RW) {
    1551             :                                         /* these opcode use the op2 as result */
    1552           0 :                                         zend_bitset_incl(defined_here, var_num);
    1553         649 :                                 } else if (!zend_bitset_in(defined_here, var_num)) {
    1554          13 :                                         zend_bitset_incl(used_ext, var_num);
    1555             :                                 }
    1556       13835 :                         } else if (opline->op2_type == IS_TMP_VAR) {
    1557         280 :                                 var_num = VAR_NUM(opline->op2.var);
    1558         280 :                                 if (!zend_bitset_in(defined_here, var_num)) {
    1559          58 :                                         zend_bitset_incl(used_ext, var_num);
    1560             :                                 }
    1561             :                         }
    1562             : 
    1563       14484 :                         if (opline->result_type == IS_VAR) {
    1564        2329 :                                 var_num = VAR_NUM(opline->result.var);
    1565        2329 :                                 zend_bitset_incl(defined_here, var_num);
    1566       12155 :                         } else if (opline->result_type == IS_TMP_VAR) {
    1567        2375 :                                 var_num = VAR_NUM(opline->result.var);
    1568        2375 :                                 switch (opline->opcode) {
    1569             :                                         case ZEND_ADD_ARRAY_ELEMENT:
    1570             :                                         case ZEND_ROPE_ADD:
    1571             :                                                 /* these opcodes use the result as argument */
    1572         524 :                                                 if (!zend_bitset_in(defined_here, var_num)) {
    1573         295 :                                                         zend_bitset_incl(used_ext, var_num);
    1574             :                                                 }
    1575         524 :                                                 break;
    1576             :                                         default :
    1577        1851 :                                                 zend_bitset_incl(defined_here, var_num);
    1578             :                                 }
    1579             :                         }
    1580       14484 :                         opline++;
    1581             :                 }
    1582             :         }
    1583             : 
    1584        2712 :         if (ctx->debug_level & ZEND_DUMP_BLOCK_PASS_VARS) {
    1585           0 :                 int printed = 0;
    1586             :                 uint32_t i;
    1587             : 
    1588           0 :                 for (i = op_array->last_var; i< op_array->T; i++) {
    1589           0 :                         if (zend_bitset_in(used_ext, i)) {
    1590           0 :                                 if (!printed) {
    1591           0 :                                         fprintf(stderr, "NON-LOCAL-VARS: %d", i);
    1592           0 :                                         printed = 1;
    1593             :                                 } else {
    1594           0 :                                         fprintf(stderr, ", %d", i);
    1595             :                                 }
    1596             :                         }
    1597             :                 }
    1598           0 :                 if (printed) {
    1599           0 :                         fprintf(stderr, "\n");
    1600             :                 }
    1601             :         }
    1602             : 
    1603        2712 :         usage = defined_here;
    1604        2712 :         next_block = NULL;
    1605       14420 :         for (n = cfg->blocks_count; n > 0;) {
    1606        8996 :                 block = cfg->blocks + (--n);
    1607             : 
    1608        8996 :                 if (!(block->flags & ZEND_BB_REACHABLE) || block->len == 0) {
    1609        2462 :                         continue;
    1610             :                 }
    1611             : 
    1612        6534 :                 end = op_array->opcodes + block->start;
    1613        6534 :                 opline = end + block->len - 1;
    1614       17330 :                 if (!next_block ||
    1615        3822 :                     !(next_block->flags & ZEND_BB_FOLLOW) ||
    1616        2874 :                     (next_block->flags & ZEND_BB_TARGET)) {
    1617             :                         /* Skip continuation of "extended" BB */
    1618        4100 :                         zend_bitset_copy(usage, used_ext, bitset_len);
    1619        2434 :                 } else if (block->successors[1] != -1) {
    1620        1024 :                         zend_bitset_union(usage, used_ext, bitset_len);
    1621             :                 }
    1622        6534 :                 next_block = block;
    1623             : 
    1624       48113 :                 while (opline >= end) {
    1625             :                         /* usage checks */
    1626       35045 :                         if (opline->result_type == IS_VAR) {
    1627        5136 :                                 if (!zend_bitset_in(usage, VAR_NUM(opline->result.var))) {
    1628          12 :                                         switch (opline->opcode) {
    1629             :                                                 case ZEND_ASSIGN_ADD:
    1630             :                                                 case ZEND_ASSIGN_SUB:
    1631             :                                                 case ZEND_ASSIGN_MUL:
    1632             :                                                 case ZEND_ASSIGN_DIV:
    1633             :                                                 case ZEND_ASSIGN_POW:
    1634             :                                                 case ZEND_ASSIGN_MOD:
    1635             :                                                 case ZEND_ASSIGN_SL:
    1636             :                                                 case ZEND_ASSIGN_SR:
    1637             :                                                 case ZEND_ASSIGN_CONCAT:
    1638             :                                                 case ZEND_ASSIGN_BW_OR:
    1639             :                                                 case ZEND_ASSIGN_BW_AND:
    1640             :                                                 case ZEND_ASSIGN_BW_XOR:
    1641             :                                                 case ZEND_PRE_INC:
    1642             :                                                 case ZEND_PRE_DEC:
    1643             :                                                 case ZEND_ASSIGN:
    1644             :                                                 case ZEND_ASSIGN_REF:
    1645             :                                                 case ZEND_DO_FCALL:
    1646             :                                                 case ZEND_DO_ICALL:
    1647             :                                                 case ZEND_DO_UCALL:
    1648             :                                                 case ZEND_DO_FCALL_BY_NAME:
    1649           0 :                                                         opline->result_type = IS_UNUSED;
    1650             :                                                         break;
    1651             :                                         }
    1652             :                                 } else {
    1653        5124 :                                         zend_bitset_excl(usage, VAR_NUM(opline->result.var));
    1654             :                                 }
    1655       29909 :                         } else if (opline->result_type == IS_TMP_VAR) {
    1656        3091 :                                 if (!zend_bitset_in(usage, VAR_NUM(opline->result.var))) {
    1657          59 :                                         switch (opline->opcode) {
    1658             :                                                 case ZEND_POST_INC:
    1659             :                                                 case ZEND_POST_DEC:
    1660           0 :                                                         opline->opcode -= 2;
    1661           0 :                                                         opline->result_type = IS_UNUSED;
    1662           0 :                                                         break;
    1663             :                                                 case ZEND_QM_ASSIGN:
    1664             :                                                 case ZEND_BOOL:
    1665             :                                                 case ZEND_BOOL_NOT:
    1666           4 :                                                         if (ZEND_OP1_TYPE(opline) == IS_CV) {
    1667           0 :                                                                 opline->opcode = ZEND_CHECK_VAR;
    1668           0 :                                                                 SET_UNUSED(opline->result);
    1669           4 :                                                         } else if (ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) {
    1670           1 :                                                                 opline->opcode = ZEND_FREE;
    1671           1 :                                                                 SET_UNUSED(opline->result);
    1672             :                                                         } else {
    1673           3 :                                                                 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
    1674           6 :                                                                         literal_dtor(&ZEND_OP1_LITERAL(opline));
    1675             :                                                                 }
    1676           3 :                                                                 MAKE_NOP(opline);
    1677             :                                                         }
    1678           4 :                                                         break;
    1679             :                                                 case ZEND_JMPZ_EX:
    1680             :                                                 case ZEND_JMPNZ_EX:
    1681          55 :                                                         opline->opcode -= 3;
    1682          55 :                                                         SET_UNUSED(opline->result);
    1683          55 :                                                         break;
    1684             :                                                 case ZEND_ADD_ARRAY_ELEMENT:
    1685             :                                                 case ZEND_ROPE_ADD:
    1686           0 :                                                         zend_bitset_incl(usage, VAR_NUM(opline->result.var));
    1687             :                                                         break;
    1688             :                                         }
    1689             :                                 } else {
    1690        3032 :                                         switch (opline->opcode) {
    1691             :                                                 case ZEND_ADD_ARRAY_ELEMENT:
    1692             :                                                 case ZEND_ROPE_ADD:
    1693         524 :                                                         break;
    1694             :                                                 default:
    1695        2508 :                                                         zend_bitset_excl(usage, VAR_NUM(opline->result.var));
    1696             :                                                         break;
    1697             :                                         }
    1698             :                                 }
    1699             :                         }
    1700             : 
    1701       35045 :                         if (opline->op2_type == IS_VAR) {
    1702        1020 :                                 switch (opline->opcode) {
    1703             :                                         case ZEND_FE_FETCH_R:
    1704             :                                         case ZEND_FE_FETCH_RW:
    1705           0 :                                                 zend_bitset_excl(usage, VAR_NUM(opline->op2.var));
    1706           0 :                                                 break;
    1707             :                                         default:
    1708        1020 :                                                 zend_bitset_incl(usage, VAR_NUM(opline->op2.var));
    1709             :                                                 break;
    1710             :                                 }
    1711       34025 :                         } else if (opline->op2_type == IS_TMP_VAR) {
    1712         363 :                                 zend_bitset_incl(usage, VAR_NUM(opline->op2.var));
    1713             :                         }
    1714             : 
    1715       35045 :                         if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
    1716        6519 :                                 zend_bitset_incl(usage, VAR_NUM(opline->op1.var));
    1717             :                         }
    1718             : 
    1719       35045 :                         opline--;
    1720             :                 }
    1721             :         }
    1722             : 
    1723        2712 :         zend_arena_release(&ctx->arena, checkpoint);
    1724             : }
    1725             : 
    1726        2178 : static void zend_merge_blocks(zend_op_array *op_array, zend_cfg *cfg)
    1727             : {
    1728             :         int i;
    1729             :         zend_basic_block *b, *bb;
    1730        2178 :         zend_basic_block *prev = NULL;
    1731             : 
    1732        9126 :         for (i = 0; i < cfg->blocks_count; i++) {
    1733        6948 :                 b = cfg->blocks + i;
    1734        6948 :                 if (b->flags & ZEND_BB_REACHABLE) {
    1735        8809 :                         if ((b->flags & ZEND_BB_FOLLOW) &&
    1736        2333 :                             !(b->flags & (ZEND_BB_TARGET | ZEND_BB_PROTECTED)) &&
    1737             :                             prev &&
    1738        1164 :                             prev->successors[0] == i && prev->successors[1] == -1)
    1739             :                         {
    1740         277 :                                 zend_op *last_op = op_array->opcodes + prev->start + prev->len - 1;
    1741         277 :                                 if (prev->len != 0 && last_op->opcode == ZEND_JMP) {
    1742           0 :                                         MAKE_NOP(last_op);
    1743             :                                 }
    1744             : 
    1745         661 :                                 for (bb = prev + 1; bb != b; bb++) {
    1746         384 :                                         zend_op *op = op_array->opcodes + bb->start;
    1747         384 :                                         zend_op *end = op + bb->len;
    1748        1320 :                                         while (op < end) {
    1749         552 :                                                 if (ZEND_OP1_TYPE(op) == IS_CONST) {
    1750         678 :                                                         literal_dtor(&ZEND_OP1_LITERAL(op));
    1751             :                                                 }
    1752         552 :                                                 if (ZEND_OP2_TYPE(op) == IS_CONST) {
    1753         122 :                                                         literal_dtor(&ZEND_OP2_LITERAL(op));
    1754             :                                                 }
    1755         552 :                                                 MAKE_NOP(op);
    1756         552 :                                                 op++;
    1757             :                                         }
    1758             :                                         /* make block empty */
    1759         384 :                                         bb->len = 0;
    1760             :                                 }
    1761             : 
    1762             :                                 /* re-link */
    1763         277 :                                 prev->flags |= (b->flags & ZEND_BB_EXIT);
    1764         277 :                                 prev->len = b->start + b->len - prev->start;
    1765         277 :                                 prev->successors[0] = b->successors[0];
    1766         277 :                                 prev->successors[1] = b->successors[1];
    1767             : 
    1768             :                                 /* unlink & make block empty and unreachable */
    1769         277 :                                 b->flags = 0;
    1770         277 :                                 b->len = 0;
    1771         277 :                                 b->successors[0] = -1;
    1772         277 :                                 b->successors[1] = -1;
    1773             :                         } else {
    1774        4758 :                                 prev = b;
    1775             :                         }
    1776             :                 }
    1777             :         }
    1778        2178 : }
    1779             : 
    1780             : #define PASSES 3
    1781             : 
    1782         726 : void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
    1783             : {
    1784             :         zend_cfg cfg;
    1785             :         zend_basic_block *blocks, *end, *b;
    1786             :         int pass;
    1787             :         uint32_t bitset_len;
    1788             :         zend_bitset usage;
    1789             :         void *checkpoint;
    1790             :         zend_op **Tsource;
    1791             :         zend_uchar *same_t;
    1792             : 
    1793             :     /* Build CFG */
    1794        1452 :         checkpoint = zend_arena_checkpoint(ctx->arena);
    1795         726 :         if (zend_build_cfg(&ctx->arena, op_array, ZEND_CFG_SPLIT_AT_LIVE_RANGES, &cfg, NULL) != SUCCESS) {
    1796           0 :                 zend_arena_release(&ctx->arena, checkpoint);
    1797           0 :                 return;
    1798             :         }
    1799             : 
    1800         726 :         if (cfg.blocks_count * (op_array->last_var + op_array->T) > 64 * 1024 * 1024) {
    1801           0 :                 zend_arena_release(&ctx->arena, checkpoint);
    1802           0 :                 return;
    1803             :         }
    1804             : 
    1805         726 :         if (ctx->debug_level & ZEND_DUMP_BEFORE_BLOCK_PASS) {
    1806           0 :                 zend_dump_op_array(op_array, ZEND_DUMP_CFG, "before block pass", &cfg);
    1807             :         }
    1808             : 
    1809        1411 :         if (op_array->last_var || op_array->T) {
    1810         685 :                 bitset_len = zend_bitset_len(op_array->last_var + op_array->T);
    1811        1370 :                 Tsource = zend_arena_calloc(&ctx->arena, op_array->last_var + op_array->T, sizeof(zend_op *));
    1812        1370 :                 same_t = zend_arena_alloc(&ctx->arena, op_array->last_var + op_array->T);
    1813        1370 :                 usage = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
    1814             :         } else {
    1815          41 :                 bitset_len = 0;
    1816          41 :                 Tsource = NULL;
    1817          41 :                 same_t = NULL;
    1818          41 :                 usage = NULL;
    1819             :         }
    1820         726 :         blocks = cfg.blocks;
    1821         726 :         end = blocks + cfg.blocks_count;
    1822        2904 :         for (pass = 0; pass < PASSES; pass++) {
    1823             :                 /* Compute data dependencies */
    1824        2178 :                 zend_bitset_clear(usage, bitset_len);
    1825        2178 :                 zend_t_usage(&cfg, op_array, usage, ctx);
    1826             : 
    1827             :                 /* optimize each basic block separately */
    1828        9126 :                 for (b = blocks; b < end; b++) {
    1829        6948 :                         if (!(b->flags & ZEND_BB_REACHABLE)) {
    1830        1794 :                                 continue;
    1831             :                         }
    1832             :                         /* we track data dependencies only insight a single basic block */
    1833        7349 :                         if (!(b->flags & ZEND_BB_FOLLOW) ||
    1834        2195 :                             (b->flags & ZEND_BB_TARGET)) {
    1835             :                                 /* Skip continuation of "extended" BB */
    1836        3299 :                                 memset(Tsource, 0, (op_array->last_var + op_array->T) * sizeof(zend_op *));
    1837             :                         }
    1838        5154 :                         zend_optimize_block(b, op_array, usage, &cfg, Tsource);
    1839             :                 }
    1840             : 
    1841             :                 /* Jump optimization for each block */
    1842        9126 :                 for (b = blocks; b < end; b++) {
    1843        6948 :                         if (b->flags & ZEND_BB_REACHABLE) {
    1844        5154 :                                 zend_jmp_optimization(b, op_array, &cfg, same_t);
    1845             :                         }
    1846             :                 }
    1847             : 
    1848             :                 /* Eliminate unreachable basic blocks */
    1849        2178 :                 zend_cfg_remark_reachable_blocks(op_array, &cfg);
    1850             : 
    1851             :                 /* Merge Blocks */
    1852        2178 :                 zend_merge_blocks(op_array, &cfg);
    1853             :         }
    1854             : 
    1855         726 :         zend_bitset_clear(usage, bitset_len);
    1856         726 :         zend_t_usage(&cfg, op_array, usage, ctx);
    1857         726 :         assemble_code_blocks(&cfg, op_array);
    1858             : 
    1859         726 :         if (ctx->debug_level & ZEND_DUMP_AFTER_BLOCK_PASS) {
    1860           0 :                 zend_dump_op_array(op_array, ZEND_DUMP_CFG | ZEND_DUMP_HIDE_UNREACHABLE, "after block pass", &cfg);
    1861             :         }
    1862             : 
    1863             :         /* Destroy CFG */
    1864         726 :         zend_arena_release(&ctx->arena, checkpoint);
    1865             : }

Generated by: LCOV version 1.10

Generated at Sun, 15 Oct 2017 12:26:22 +0000 (8 days ago)

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