]> granicus.if.org Git - php/commitdiff
Merge branch 'PHP-7.0'
authorDmitry Stogov <dmitry@zend.com>
Thu, 18 Feb 2016 20:18:56 +0000 (23:18 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 18 Feb 2016 20:18:56 +0000 (23:18 +0300)
* PHP-7.0:
  Set proper type flags (REFCOUNTED and COPYABLE) according to interned or regular string

1  2 
ext/opcache/Optimizer/block_pass.c

index df99eb5e99d75f25a72f1813bf90de0f225b7485,15e6511a764ba9015db96abaa8663b46e9317bad..4f4dd8e11a0759f5da08bc33a74aeace61940637
@@@ -172,98 -654,47 +172,95 @@@ static void zend_optimize_block(zend_ba
                        }
                }
  
 -              /* T = QM_ASSIGN(C), F(T) => NOP, F(C) */
 -              if ((ZEND_OP2_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
 -                      VAR_SOURCE(opline->op2) &&
 -                      VAR_SOURCE(opline->op2)->opcode == ZEND_QM_ASSIGN &&
 -                      ZEND_OP1_TYPE(VAR_SOURCE(opline->op2)) == IS_CONST) {
 -                      znode_op op2 = opline->op2;
 -                      zend_op *src = VAR_SOURCE(op2);
 -                      zval c = ZEND_OP1_LITERAL(src);
 -                      zval_copy_ctor(&c);
 -                      if (zend_optimizer_update_op2_const(op_array, opline, &c)) {
 -                              VAR_SOURCE(op2) = NULL;
 -                              literal_dtor(&ZEND_OP1_LITERAL(src));
 -                              MAKE_NOP(src);
 +              if (opline->opcode == ZEND_ECHO) {
 +                      if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
 +                              src = VAR_SOURCE(opline->op1);
 +                              if (src &&
 +                                  src->opcode == ZEND_CAST &&
 +                                  src->extended_value == IS_STRING) {
 +                                      /* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */
 +                                      VAR_SOURCE(opline->op1) = NULL;
 +                                      COPY_NODE(opline->op1, src->op1);
 +                                      MAKE_NOP(src);
 +                              }
                        }
 -              }
  
 -              /* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */
 -              if (opline->opcode == ZEND_ECHO &&
 -                      ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR) &&
 -                      VAR_SOURCE(opline->op1) &&
 -                      VAR_SOURCE(opline->op1)->opcode == ZEND_CAST &&
 -                      VAR_SOURCE(opline->op1)->extended_value == IS_STRING) {
 -                      zend_op *src = VAR_SOURCE(opline->op1);
 -                      COPY_NODE(opline->op1, src->op1);
 -                      MAKE_NOP(src);
 -              }
 +                      if (opline->op1_type == IS_CONST) {
 +                              if (last_op && last_op->opcode == ZEND_ECHO &&
 +                                  last_op->op1_type == IS_CONST &&
 +                                  Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_DOUBLE &&
 +                                  Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_DOUBLE) {
 +                                      /* compress consecutive ECHO's.
 +                                       * Float to string conversion may be affected by current
 +                                       * locale setting.
 +                                       */
 +                                      int l, old_len;
  
 -       /* T = BOOL(X), FREE(T) => NOP */
 -              if (opline->opcode == ZEND_FREE &&
 -                      ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
 -                      VAR_SOURCE(opline->op1)) {
 -                      zend_op *src = VAR_SOURCE(opline->op1);
 -                      if (src->opcode == ZEND_BOOL) {
 -                              if (ZEND_OP1_TYPE(src) == IS_CONST) {
 -                                      literal_dtor(&ZEND_OP1_LITERAL(src));
 +                                      if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
 +                                              convert_to_string_safe(&ZEND_OP1_LITERAL(opline));
 +                                      }
 +                                      if (Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_STRING) {
 +                                              convert_to_string_safe(&ZEND_OP1_LITERAL(last_op));
 +                                      }
 +                                      old_len = Z_STRLEN(ZEND_OP1_LITERAL(last_op));
 +                                      l = old_len + Z_STRLEN(ZEND_OP1_LITERAL(opline));
 +                                      if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(last_op))) {
 +                                              zend_string *tmp = zend_string_alloc(l, 0);
-                                       memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP1_LITERAL(last_op)), old_len);
++                                              memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP1_LITERAL(last_op)), old_len);
 +                                              Z_STR(ZEND_OP1_LITERAL(last_op)) = tmp;
 +                                      } else {
 +                                              Z_STR(ZEND_OP1_LITERAL(last_op)) = zend_string_extend(Z_STR(ZEND_OP1_LITERAL(last_op)), l, 0);
 +                                      }
 +                                      Z_TYPE_INFO(ZEND_OP1_LITERAL(last_op)) = IS_STRING_EX;
 +                                      memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op)) + old_len, Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)));
 +                                      Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0';
 +                                      zval_dtor(&ZEND_OP1_LITERAL(opline));
-                                       Z_STR(ZEND_OP1_LITERAL(opline)) = zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op)));
-                                       if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(opline))) {
-                                               Z_TYPE_FLAGS(ZEND_OP1_LITERAL(opline)) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE);
-                                       }
++                                      ZVAL_STR(&ZEND_OP1_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op))));
 +                                      ZVAL_NULL(&ZEND_OP1_LITERAL(last_op));
 +                                      MAKE_NOP(last_op);
                                }
 -                              MAKE_NOP(src);
 -                              MAKE_NOP(opline);
 +                              last_op = opline;
 +                      } else {
 +                              last_op = NULL;
                        }
 +              } else {
 +                      last_op = NULL;
                }
  
 +              switch (opline->opcode) {
 +
 +                      case ZEND_FREE:
 +                              if (opline->op1_type == IS_TMP_VAR) {
 +                                      src = VAR_SOURCE(opline->op1);
 +                                      if (src &&
 +                                          (src->opcode == ZEND_BOOL || src->opcode == ZEND_BOOL_NOT)) {
 +                                              /* T = BOOL(X), FREE(T) => NOP */
 +                                              if (ZEND_OP1_TYPE(src) == IS_CONST) {
 +                                                      literal_dtor(&ZEND_OP1_LITERAL(src));
 +                                              }
 +                                              VAR_SOURCE(opline->op1) = NULL;
 +                                              MAKE_NOP(src);
 +                                              MAKE_NOP(opline);
 +                                      }
 +                              } else if (opline->op1_type == IS_VAR) {
 +                                      src = VAR_SOURCE(opline->op1);
 +                                      /* V = OP, FREE(V) => OP. NOP */
 +                                      if (src &&
 +                                          src->opcode != ZEND_FETCH_R &&
 +                                          src->opcode != ZEND_FETCH_STATIC_PROP_R &&
 +                                          src->opcode != ZEND_FETCH_DIM_R &&
 +                                          src->opcode != ZEND_FETCH_OBJ_R &&
 +                                          src->opcode != ZEND_NEW) {
 +                                              if (opline->extended_value & ZEND_FREE_ON_RETURN) {
 +                                                      /* mark as removed (empty live range) */
 +                                                      op_array->live_range[opline->op2.num].var = (uint32_t)-1;
 +                                              }
 +                                              ZEND_RESULT_TYPE(src) = IS_UNUSED;
 +                                              MAKE_NOP(opline);
 +                                      }
 +                              }
 +                              break;
 +
  #if 0
                /* pre-evaluate functions:
                   constant(x)
                }
  #endif
  
 -        /* IS_EQ(TRUE, X)      => BOOL(X)
 -         * IS_EQ(FALSE, X)     => BOOL_NOT(X)
 -         * IS_NOT_EQ(TRUE, X)  => BOOL_NOT(X)
 -         * IS_NOT_EQ(FALSE, X) => BOOL(X)
 -         * CASE(TRUE, X)       => BOOL(X)
 -         * CASE(FALSE, X)      => BOOL_NOT(X)
 -         */
 -              if (opline->opcode == ZEND_IS_EQUAL ||
 -                      opline->opcode == ZEND_IS_NOT_EQUAL ||
 -                      /* CASE variable will be deleted later by FREE, so we can't optimize it */
 -                      (opline->opcode == ZEND_CASE && (ZEND_OP1_TYPE(opline) & (IS_CONST|IS_CV)))) {
 -                      if (ZEND_OP1_TYPE(opline) == IS_CONST &&
 -                              (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_FALSE ||
 -                               Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_TRUE)) {
 -                              /* T = IS_EQUAL(TRUE,  X)     => T = BOOL(X) */
 -                              /* T = IS_EQUAL(FALSE, X)     => T = BOOL_NOT(X) */
 -                              /* T = IS_NOT_EQUAL(TRUE,  X) => T = BOOL_NOT(X) */
 -                              /* T = IS_NOT_EQUAL(FALSE, X) => T = BOOL(X) */
 -                              /* Optimization of comparison with "null" is not safe,
 -                               * because ("0" == null) is not equal to !("0")
 -                               */
 -                              opline->opcode =
 -                                      ((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP1_LITERAL(opline))) == IS_TRUE)) ?
 -                                      ZEND_BOOL : ZEND_BOOL_NOT;
 -                              COPY_NODE(opline->op1, opline->op2);
 -                              SET_UNUSED(opline->op2);
 -                      } else if (ZEND_OP2_TYPE(opline) == IS_CONST &&
 -                                         (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_FALSE ||
 -                                          Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_TRUE)) {
 -                              /* T = IS_EQUAL(X, TRUE)      => T = BOOL(X) */
 -                              /* T = IS_EQUAL(X, FALSE)     => T = BOOL_NOT(X) */
 -                              /* T = IS_NOT_EQUAL(X, TRUE)  => T = BOOL_NOT(X) */
 -                              /* T = IS_NOT_EQUAL(X, FALSE) => T = BOOL(X) */
 -                              /* Optimization of comparison with "null" is not safe,
 -                               * because ("0" == null) is not equal to !("0")
 -                               */
 -                              opline->opcode =
 -                                      ((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP2_LITERAL(opline))) == IS_TRUE)) ?
 -                                      ZEND_BOOL : ZEND_BOOL_NOT;
 -                              SET_UNUSED(opline->op2);
 -                      }
 -              }
 +                      case ZEND_FETCH_LIST:
 +                              if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
 +                                      /* LIST variable will be deleted later by FREE */
 +                                      Tsource[VAR_NUM(opline->op1.var)] = NULL;
 +                              }
 +                              break;
  
 -              if ((opline->opcode == ZEND_BOOL ||
 -                      opline->opcode == ZEND_BOOL_NOT ||
 -                      opline->opcode == ZEND_JMPZ ||
 -                      opline->opcode == ZEND_JMPNZ ||
 -                      opline->opcode == ZEND_JMPZNZ) &&
 -                      ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
 -                      VAR_SOURCE(opline->op1) != NULL &&
 -                      !zend_bitset_in(used_ext, VAR_NUM(ZEND_OP1(opline).var)) &&
 -                      VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL_NOT) {
 -                      /* T = BOOL_NOT(X) + JMPZ(T) -> NOP, JMPNZ(X) */
 -                      zend_op *src = VAR_SOURCE(opline->op1);
 -
 -                      COPY_NODE(opline->op1, src->op1);
 -
 -                      switch (opline->opcode) {
 -                              case ZEND_BOOL:
 -                                      /* T = BOOL_NOT(X) + BOOL(T) -> NOP, BOOL_NOT(X) */
 -                                      opline->opcode = ZEND_BOOL_NOT;
 -                                      break;
 -                              case ZEND_BOOL_NOT:
 -                                      /* T = BOOL_NOT(X) + BOOL_BOOL(T) -> NOP, BOOL(X) */
 -                                      opline->opcode = ZEND_BOOL;
 +                      case ZEND_CASE:
 +                              if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
 +                                      /* CASE variable will be deleted later by FREE, so we can't optimize it */
 +                                      Tsource[VAR_NUM(opline->op1.var)] = NULL;
                                        break;
 -                              case ZEND_JMPZ:
 -                                      /* T = BOOL_NOT(X) + JMPZ(T,L) -> NOP, JMPNZ(X,L) */
 -                                      opline->opcode = ZEND_JMPNZ;
 -                                      break;
 -                              case ZEND_JMPNZ:
 -                                      /* T = BOOL_NOT(X) + JMPNZ(T,L) -> NOP, JMPZ(X,L) */
 -                                      opline->opcode = ZEND_JMPZ;
 +                              }
 +                              if (opline->op1_type == IS_CONST &&
 +                                  opline->op2_type == IS_CONST) {
                                        break;
 -                              case ZEND_JMPZNZ:
 -                              {
 -                                      /* T = BOOL_NOT(X) + JMPZNZ(T,L1,L2) -> NOP, JMPZNZ(X,L2,L1) */
 -                                      int op_t;
 -                                      zend_code_block *op_b;
 -
 -                                      op_t = opline->extended_value;
 -                                      opline->extended_value = ZEND_OP2(opline).opline_num;
 -                                      ZEND_OP2(opline).opline_num = op_t;
 -
 -                                      op_b = block->ext_to;
 -                                      block->ext_to = block->op2_to;
 -                                      block->op2_to = op_b;
 +                              }
 +                              /* break missing intentionally */
 +
 +                      case ZEND_IS_EQUAL:
 +                      case ZEND_IS_NOT_EQUAL:
 +                              if (opline->op1_type == IS_CONST &&
 +                                  opline->op2_type == IS_CONST) {
 +                                      goto optimize_constant_binary_op;
 +                              }
 +                      /* IS_EQ(TRUE, X)      => BOOL(X)
 +                       * IS_EQ(FALSE, X)     => BOOL_NOT(X)
 +                       * IS_NOT_EQ(TRUE, X)  => BOOL_NOT(X)
 +                       * IS_NOT_EQ(FALSE, X) => BOOL(X)
 +                       * CASE(TRUE, X)       => BOOL(X)
 +                       * CASE(FALSE, X)      => BOOL_NOT(X)
 +                       */
 +                              if (opline->op1_type == IS_CONST &&
 +                                      (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_FALSE ||
 +                                       Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_TRUE)) {
 +                                      /* Optimization of comparison with "null" is not safe,
 +                                       * because ("0" == null) is not equal to !("0")
 +                                       */
 +                                      opline->opcode =
 +                                              ((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP1_LITERAL(opline))) == IS_TRUE)) ?
 +                                              ZEND_BOOL : ZEND_BOOL_NOT;
 +                                      COPY_NODE(opline->op1, opline->op2);
 +                                      SET_UNUSED(opline->op2);
 +                                      goto optimize_bool;
 +                              } else if (opline->op2_type == IS_CONST &&
 +                                         (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_FALSE ||
 +                                          Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_TRUE)) {
 +                                      /* Optimization of comparison with "null" is not safe,
 +                                       * because ("0" == null) is not equal to !("0")
 +                                       */
 +                                      opline->opcode =
 +                                              ((opline->opcode != ZEND_IS_NOT_EQUAL) == ((Z_TYPE(ZEND_OP2_LITERAL(opline))) == IS_TRUE)) ?
 +                                              ZEND_BOOL : ZEND_BOOL_NOT;
 +                                      SET_UNUSED(opline->op2);
 +                                      goto optimize_bool;
                                }
                                break;
 -                      }
  
 -                      VAR_UNSET(opline->op1);
 -                      MAKE_NOP(src);
 -                      continue;
 -              } else
 +                      case ZEND_BOOL:
 +                      case ZEND_BOOL_NOT:
 +                      optimize_bool:
 +                              if (opline->op1_type == IS_CONST) {
 +                                      goto optimize_const_unary_op;
 +                              }
 +                              if (opline->op1_type == IS_TMP_VAR &&
 +                                  !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
 +                                      src = VAR_SOURCE(opline->op1);
 +                                      if (src) {
 +                                              switch (src->opcode) {
 +                                                      case ZEND_BOOL_NOT:
 +                                                              /* T = BOOL_NOT(X) + BOOL(T) -> NOP, BOOL_NOT(X) */
 +                                                              VAR_SOURCE(opline->op1) = NULL;
 +                                                              COPY_NODE(opline->op1, src->op1);
 +                                                              opline->opcode = (opline->opcode == ZEND_BOOL) ? ZEND_BOOL_NOT : ZEND_BOOL;
 +                                                              MAKE_NOP(src);
 +                                                              goto optimize_bool;
 +                                                      case ZEND_BOOL:
 +                                                              /* T = BOOL(X) + BOOL(T) -> NOP, BOOL(X) */
 +                                                              VAR_SOURCE(opline->op1) = NULL;
 +                                                              COPY_NODE(opline->op1, src->op1);
 +                                                              MAKE_NOP(src);
 +                                                              goto optimize_bool;
 +                                                      case ZEND_IS_EQUAL:
 +                                                              if (opline->opcode == ZEND_BOOL_NOT) {
 +                                                                      src->opcode = ZEND_IS_NOT_EQUAL;
 +                                                              }
 +                                                              COPY_NODE(src->result, opline->result);
 +                                                              SET_VAR_SOURCE(src);
 +                                                              MAKE_NOP(opline);
 +                                                              break;
 +                                                      case ZEND_IS_NOT_EQUAL:
 +                                                              if (opline->opcode == ZEND_BOOL_NOT) {
 +                                                                      src->opcode = ZEND_IS_EQUAL;
 +                                                              }
 +                                                              COPY_NODE(src->result, opline->result);
 +                                                              SET_VAR_SOURCE(src);
 +                                                              MAKE_NOP(opline);
 +                                                              break;
 +                                                      case ZEND_IS_IDENTICAL:
 +                                                              if (opline->opcode == ZEND_BOOL_NOT) {
 +                                                                      src->opcode = ZEND_IS_NOT_IDENTICAL;
 +                                                              }
 +                                                              COPY_NODE(src->result, opline->result);
 +                                                              SET_VAR_SOURCE(src);
 +                                                              MAKE_NOP(opline);
 +                                                              break;
 +                                                      case ZEND_IS_NOT_IDENTICAL:
 +                                                              if (opline->opcode == ZEND_BOOL_NOT) {
 +                                                                      src->opcode = ZEND_IS_IDENTICAL;
 +                                                              }
 +                                                              COPY_NODE(src->result, opline->result);
 +                                                              SET_VAR_SOURCE(src);
 +                                                              MAKE_NOP(opline);
 +                                                              break;
 +                                                      case ZEND_IS_SMALLER:
 +                                                              if (opline->opcode == ZEND_BOOL_NOT) {
 +                                                                      zend_uchar tmp_type;
 +                                                                      uint32_t tmp;
 +
 +                                                                      src->opcode = ZEND_IS_SMALLER_OR_EQUAL;
 +                                                                      tmp_type = src->op1_type;
 +                                                                      src->op1_type = src->op2_type;
 +                                                                      src->op2_type = tmp_type;
 +                                                                      tmp = src->op1.num;
 +                                                                      src->op1.num = src->op2.num;
 +                                                                      src->op2.num = tmp;
 +                                                              }
 +                                                              COPY_NODE(src->result, opline->result);
 +                                                              SET_VAR_SOURCE(src);
 +                                                              MAKE_NOP(opline);
 +                                                              break;
 +                                                      case ZEND_IS_SMALLER_OR_EQUAL:
 +                                                              if (opline->opcode == ZEND_BOOL_NOT) {
 +                                                                      zend_uchar tmp_type;
 +                                                                      uint32_t tmp;
 +
 +                                                                      src->opcode = ZEND_IS_SMALLER;
 +                                                                      tmp_type = src->op1_type;
 +                                                                      src->op1_type = src->op2_type;
 +                                                                      src->op2_type = tmp_type;
 +                                                                      tmp = src->op1.num;
 +                                                                      src->op1.num = src->op2.num;
 +                                                                      src->op2.num = tmp;
 +                                                              }
 +                                                              COPY_NODE(src->result, opline->result);
 +                                                              SET_VAR_SOURCE(src);
 +                                                              MAKE_NOP(opline);
 +                                                              break;
 +                                                      case ZEND_ISSET_ISEMPTY_VAR:
 +                                                      case ZEND_ISSET_ISEMPTY_DIM_OBJ:
 +                                                      case ZEND_ISSET_ISEMPTY_PROP_OBJ:
 +                                                      case ZEND_ISSET_ISEMPTY_STATIC_PROP:
 +                                                      case ZEND_INSTANCEOF:
 +                                                      case ZEND_TYPE_CHECK:
 +                                                      case ZEND_DEFINED:
 +                                                              if (opline->opcode == ZEND_BOOL_NOT) {
 +                                                                      break;
 +                                                              }
 +                                                              COPY_NODE(src->result, opline->result);
 +                                                              SET_VAR_SOURCE(src);
 +                                                              MAKE_NOP(opline);
 +                                                              break;
 +                                              }
 +                                      }
 +                              }
 +                              break;
 +
 +                      case ZEND_JMPZ:
 +                      case ZEND_JMPNZ:
 +                      case ZEND_JMPZ_EX:
 +                      case ZEND_JMPNZ_EX:
 +                      case ZEND_JMPZNZ:
 +                      optimize_jmpznz:
 +                              if (opline->op1_type == IS_TMP_VAR &&
 +                                  (!zend_bitset_in(used_ext, VAR_NUM(opline->op1.var)) ||
 +                                   (opline->result_type == opline->op1_type &&
 +                                    opline->result.var == opline->op1.var))) {
 +                                      src = VAR_SOURCE(opline->op1);
 +                                      if (src) {
 +                                              if (src->opcode == ZEND_BOOL_NOT &&
 +                                                  opline->opcode != ZEND_JMPZ_EX &&
 +                                                  opline->opcode != ZEND_JMPNZ_EX) {
 +                                                      VAR_SOURCE(opline->op1) = NULL;
 +                                                      COPY_NODE(opline->op1, src->op1);
 +                                                      if (opline->opcode == ZEND_JMPZ) {
 +                                                              /* T = BOOL_NOT(X) + JMPZ(T) -> NOP, JMPNZ(X) */
 +                                                              opline->opcode = ZEND_JMPNZ;
 +                                                      } else if (opline->opcode == ZEND_JMPNZ) {
 +                                                              /* T = BOOL_NOT(X) + JMPNZ(T) -> NOP, JMPZ(X) */
 +                                                              opline->opcode = ZEND_JMPZ;
  #if 0
 -              /* T = BOOL_NOT(X) + T = JMPZ_EX(T, X) -> T = BOOL_NOT(X), JMPNZ(X) */
 -              if(0 && (opline->opcode == ZEND_JMPZ_EX ||
 -                      opline->opcode == ZEND_JMPNZ_EX) &&
 -                 ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
 -                 VAR_SOURCE(opline->op1) != NULL &&
 -                 VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL_NOT &&
 -                 ZEND_OP1(opline).var == ZEND_RESULT(opline).var
 -                 ) {
 -                      zend_op *src = VAR_SOURCE(opline->op1);
 -                      if(opline->opcode == ZEND_JMPZ_EX) {
 -                              opline->opcode = ZEND_JMPNZ;
 -                      } else {
 -                              opline->opcode = ZEND_JMPZ;
 -                      }
 -                      COPY_NODE(opline->op1, src->op1);
 -                      SET_UNUSED(opline->result);
 -                      continue;
 -              } else
 +                                                      } else if (opline->opcode == ZEND_JMPZ_EX) {
 +                                                              /* T = BOOL_NOT(X) + JMPZ_EX(T) -> NOP, JMPNZ_EX(X) */
 +                                                              opline->opcode = ZEND_JMPNZ_EX;
 +                                                      } else if (opline->opcode == ZEND_JMPNZ_EX) {
 +                                                              /* T = BOOL_NOT(X) + JMPNZ_EX(T) -> NOP, JMPZ_EX(X) */
 +                                                              opline->opcode = ZEND_JMPZ;
  #endif
 -              /* T = BOOL(X) + JMPZ(T) -> NOP, JMPZ(X) */
 -              if ((opline->opcode == ZEND_BOOL ||
 -                      opline->opcode == ZEND_BOOL_NOT ||
 -                      opline->opcode == ZEND_JMPZ ||
 -                      opline->opcode == ZEND_JMPZ_EX ||
 -                      opline->opcode == ZEND_JMPNZ_EX ||
 -                      opline->opcode == ZEND_JMPNZ ||
 -                      opline->opcode == ZEND_JMPZNZ) &&
 -                      (ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
 -                      VAR_SOURCE(opline->op1) != NULL &&
 -                      (!zend_bitset_in(used_ext, VAR_NUM(ZEND_OP1(opline).var)) ||
 -                      ((ZEND_RESULT_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
 -                       ZEND_RESULT(opline).var == ZEND_OP1(opline).var)) &&
 -                      (VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL ||
 -                      VAR_SOURCE(opline->op1)->opcode == ZEND_QM_ASSIGN)) {
 -                      zend_op *src = VAR_SOURCE(opline->op1);
 -                      COPY_NODE(opline->op1, src->op1);
 -
 -                      VAR_UNSET(opline->op1);
 -                      MAKE_NOP(src);
 -                      continue;
 -              } else if (last_op && opline->opcode == ZEND_ECHO &&
 -                                last_op->opcode == ZEND_ECHO &&
 -                                ZEND_OP1_TYPE(opline) == IS_CONST &&
 -                                Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_DOUBLE &&
 -                                ZEND_OP1_TYPE(last_op) == IS_CONST &&
 -                                Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_DOUBLE) {
 -                      /* compress consecutive ECHO's.
 -                       * Float to string conversion may be affected by current
 -                       * locale setting.
 -                       */
 -                      int l, old_len;
 -
 -                      if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
 -                              convert_to_string_safe(&ZEND_OP1_LITERAL(opline));
 -                      }
 -                      if (Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_STRING) {
 -                              convert_to_string_safe(&ZEND_OP1_LITERAL(last_op));
 -                      }
 -                      old_len = Z_STRLEN(ZEND_OP1_LITERAL(last_op));
 -                      l = old_len + Z_STRLEN(ZEND_OP1_LITERAL(opline));
 -                      if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(last_op))) {
 -                              zend_string *tmp = zend_string_alloc(l, 0);
 -                              memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP1_LITERAL(last_op)), old_len);
 -                              Z_STR(ZEND_OP1_LITERAL(last_op)) = tmp;
 -                      } else {
 -                              Z_STR(ZEND_OP1_LITERAL(last_op)) = zend_string_extend(Z_STR(ZEND_OP1_LITERAL(last_op)), l, 0);
 -                      }
 -                      Z_TYPE_INFO(ZEND_OP1_LITERAL(last_op)) = IS_STRING_EX;
 -                      memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op)) + old_len, Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)));
 -                      Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0';
 -                      zval_dtor(&ZEND_OP1_LITERAL(opline));
 -                      ZVAL_STR(&ZEND_OP1_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op))));
 -                      ZVAL_NULL(&ZEND_OP1_LITERAL(last_op));
 -                      MAKE_NOP(last_op);
 -              } else if ((opline->opcode == ZEND_CONCAT) &&
 -                                ZEND_OP2_TYPE(opline) == IS_CONST &&
 -                                ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
 -                                VAR_SOURCE(opline->op1) &&
 -                                (VAR_SOURCE(opline->op1)->opcode == ZEND_CONCAT ||
 -                                 VAR_SOURCE(opline->op1)->opcode == ZEND_FAST_CONCAT) &&
 -                                ZEND_OP2_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST &&
 -                                ZEND_RESULT(VAR_SOURCE(opline->op1)).var == ZEND_OP1(opline).var) {
 -                      /* compress consecutive CONCAT/ADD_STRING/ADD_CHARs */
 -                      zend_op *src = VAR_SOURCE(opline->op1);
 -                      int l, old_len;
 -
 -                      if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
 -                              convert_to_string_safe(&ZEND_OP2_LITERAL(opline));
 -                      }
 -                      if (Z_TYPE(ZEND_OP2_LITERAL(src)) != IS_STRING) {
 -                              convert_to_string_safe(&ZEND_OP2_LITERAL(src));
 -                      }
 +                                                      } else {
 +                                                              /* T = BOOL_NOT(X) + JMPZNZ(T,L1,L2) -> NOP, JMPZNZ(X,L2,L1) */
 +                                                              uint32_t tmp;
 +
 +                                                              ZEND_ASSERT(opline->opcode == ZEND_JMPZNZ);
 +                                                              tmp = block->successors[0];
 +                                                              block->successors[0] = block->successors[1];
 +                                                              block->successors[1] = tmp;
 +                                                      }
 +                                                      MAKE_NOP(src);
 +                                                      goto optimize_jmpznz;
 +                                              } else if (src->opcode == ZEND_BOOL ||
 +                                                         src->opcode == ZEND_QM_ASSIGN) {
 +                                                      VAR_SOURCE(opline->op1) = NULL;
 +                                                      COPY_NODE(opline->op1, src->op1);
 +                                                      MAKE_NOP(src);
 +                                                      goto optimize_jmpznz;
 +                                              }
 +                                      }
 +                              }
 +                              break;
  
 -                      VAR_UNSET(opline->op1);
 -                      COPY_NODE(opline->op1, src->op1);
 -                      old_len = Z_STRLEN(ZEND_OP2_LITERAL(src));
 -                      l = old_len + Z_STRLEN(ZEND_OP2_LITERAL(opline));
 -                      if (!Z_REFCOUNTED(ZEND_OP2_LITERAL(src))) {
 -                              zend_string *tmp = zend_string_alloc(l, 0);
 -                              memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP2_LITERAL(src)), old_len);
 -                              Z_STR(ZEND_OP2_LITERAL(last_op)) = tmp;
 -                      } else {
 -                              Z_STR(ZEND_OP2_LITERAL(src)) = zend_string_extend(Z_STR(ZEND_OP2_LITERAL(src)), l, 0);
 -                      }
 -                      Z_TYPE_INFO(ZEND_OP2_LITERAL(last_op)) = IS_STRING_EX;
 -                      memcpy(Z_STRVAL(ZEND_OP2_LITERAL(src)) + old_len, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
 -                      Z_STRVAL(ZEND_OP2_LITERAL(src))[l] = '\0';
 -                      zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline)));
 -                      ZVAL_STR(&ZEND_OP2_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP2_LITERAL(src))));
 -                      ZVAL_NULL(&ZEND_OP2_LITERAL(src));
 -                      MAKE_NOP(src);
 -              } else if ((opline->opcode == ZEND_ADD ||
 -                                      opline->opcode == ZEND_SUB ||
 -                                      opline->opcode == ZEND_MUL ||
 -                                      opline->opcode == ZEND_DIV ||
 -                                      opline->opcode == ZEND_MOD ||
 -                                      opline->opcode == ZEND_SL ||
 -                                      opline->opcode == ZEND_SR ||
 -                                      opline->opcode == ZEND_CONCAT ||
 -                                      opline->opcode == ZEND_FAST_CONCAT ||
 -                                      opline->opcode == ZEND_IS_EQUAL ||
 -                                      opline->opcode == ZEND_IS_NOT_EQUAL ||
 -                                      opline->opcode == ZEND_IS_SMALLER ||
 -                                      opline->opcode == ZEND_IS_SMALLER_OR_EQUAL ||
 -                                      opline->opcode == ZEND_IS_IDENTICAL ||
 -                                      opline->opcode == ZEND_IS_NOT_IDENTICAL ||
 -                                      opline->opcode == ZEND_BOOL_XOR ||
 -                                      opline->opcode == ZEND_BW_OR ||
 -                                      opline->opcode == ZEND_BW_AND ||
 -                                      opline->opcode == ZEND_BW_XOR) &&
 -                                      ZEND_OP1_TYPE(opline)==IS_CONST &&
 -                                      ZEND_OP2_TYPE(opline)==IS_CONST) {
 -                      /* evaluate constant expressions */
 -                      binary_op_type binary_op = get_binary_op(opline->opcode);
 -                      zval result;
 -                      int er;
 -
 -            if ((opline->opcode == ZEND_DIV || opline->opcode == ZEND_MOD) &&
 -                zval_get_long(&ZEND_OP2_LITERAL(opline)) == 0) {
 -                              if (RESULT_USED(opline)) {
 -                                      SET_VAR_SOURCE(opline);
 +                      case ZEND_CONCAT:
 +                      case ZEND_FAST_CONCAT:
 +                              if (opline->op1_type == IS_CONST &&
 +                                  opline->op2_type == IS_CONST) {
 +                                      goto optimize_constant_binary_op;
                                }
 -                opline++;
 -                              continue;
 -            } else if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR) &&
 -                zval_get_long(&ZEND_OP2_LITERAL(opline)) < 0) {
 -                              if (RESULT_USED(opline)) {
 -                                      SET_VAR_SOURCE(opline);
 +
 +                              if (opline->op2_type == IS_CONST &&
 +                                  opline->op1_type == IS_TMP_VAR) {
 +
 +                                      src = VAR_SOURCE(opline->op1);
 +                                  if (src &&
 +                                          (src->opcode == ZEND_CONCAT ||
 +                                           src->opcode == ZEND_FAST_CONCAT) &&
 +                                          src->op2_type == IS_CONST) {
 +                                              /* compress consecutive CONCATs */
 +                                              int l, old_len;
 +
 +                                              if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
 +                                                      convert_to_string_safe(&ZEND_OP2_LITERAL(opline));
 +                                              }
 +                                              if (Z_TYPE(ZEND_OP2_LITERAL(src)) != IS_STRING) {
 +                                                      convert_to_string_safe(&ZEND_OP2_LITERAL(src));
 +                                              }
 +
 +                                              VAR_SOURCE(opline->op1) = NULL;
 +                                              COPY_NODE(opline->op1, src->op1);
 +                                              old_len = Z_STRLEN(ZEND_OP2_LITERAL(src));
 +                                              l = old_len + Z_STRLEN(ZEND_OP2_LITERAL(opline));
 +                                              if (!Z_REFCOUNTED(ZEND_OP2_LITERAL(src))) {
 +                                                      zend_string *tmp = zend_string_alloc(l, 0);
 +                                                      memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP2_LITERAL(src)), old_len);
 +                                                      Z_STR(ZEND_OP2_LITERAL(src)) = tmp;
 +                                              } else {
 +                                                      Z_STR(ZEND_OP2_LITERAL(src)) = zend_string_extend(Z_STR(ZEND_OP2_LITERAL(src)), l, 0);
 +                                              }
 +                                              Z_TYPE_INFO(ZEND_OP2_LITERAL(src)) = IS_STRING_EX;
 +                                              memcpy(Z_STRVAL(ZEND_OP2_LITERAL(src)) + old_len, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)));
 +                                              Z_STRVAL(ZEND_OP2_LITERAL(src))[l] = '\0';
 +                                              zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline)));
-                                               Z_STR(ZEND_OP2_LITERAL(opline)) = zend_new_interned_string(Z_STR(ZEND_OP2_LITERAL(src)));
-                                               if (!Z_REFCOUNTED(ZEND_OP2_LITERAL(opline))) {
-                                                       Z_TYPE_FLAGS(ZEND_OP2_LITERAL(opline)) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE);
-                                               }
++                                              ZVAL_STR(&ZEND_OP2_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP2_LITERAL(src))));
 +                                              ZVAL_NULL(&ZEND_OP2_LITERAL(src));
 +                                              MAKE_NOP(src);
 +                                      }
                                }
 -                opline++;
 -                              continue;
 -                      }
 -                      er = EG(error_reporting);
 -                      EG(error_reporting) = 0;
 -                      if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
 -                              literal_dtor(&ZEND_OP1_LITERAL(opline));
 -                              literal_dtor(&ZEND_OP2_LITERAL(opline));
 -                              opline->opcode = ZEND_QM_ASSIGN;
 -                              SET_UNUSED(opline->op2);
 -                              zend_optimizer_update_op1_const(op_array, opline, &result);
 -                      }
 -                      EG(error_reporting) = er;
 -              } else if ((opline->opcode == ZEND_BOOL ||
 -                                      opline->opcode == ZEND_BOOL_NOT ||
 -                                      opline->opcode == ZEND_BW_NOT) && ZEND_OP1_TYPE(opline) == IS_CONST) {
 -                      /* evaluate constant unary ops */
 -                      unary_op_type unary_op = get_unary_op(opline->opcode);
 -                      zval result;
 -
 -                      if (unary_op) {
 -                              unary_op(&result, &ZEND_OP1_LITERAL(opline));
 -                              literal_dtor(&ZEND_OP1_LITERAL(opline));
 -                      } else {
 -                              /* BOOL */
 -                              result = ZEND_OP1_LITERAL(opline);
 -                              convert_to_boolean(&result);
 -                              ZVAL_NULL(&ZEND_OP1_LITERAL(opline));
 -                      }
 -                      opline->opcode = ZEND_QM_ASSIGN;
 -                      zend_optimizer_update_op1_const(op_array, opline, &result);
 -              } else if ((opline->opcode == ZEND_RETURN || opline->opcode == ZEND_EXIT) &&
 -                                      (ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
 -                                      VAR_SOURCE(opline->op1) &&
 -                                      VAR_SOURCE(opline->op1)->opcode == ZEND_QM_ASSIGN) {
 -                      /* T = QM_ASSIGN(X), RETURN(T) to RETURN(X) */
 -                      zend_op *src = VAR_SOURCE(opline->op1);
 -                      VAR_UNSET(opline->op1);
 -                      COPY_NODE(opline->op1, src->op1);
 -                      MAKE_NOP(src);
 -              } else if (opline->opcode == ZEND_CONCAT || opline->opcode == ZEND_FAST_CONCAT) {
 -                      if ((ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
 -                              VAR_SOURCE(opline->op1) &&
 -                              VAR_SOURCE(opline->op1)->opcode == ZEND_CAST &&
 -                              VAR_SOURCE(opline->op1)->extended_value == IS_STRING) {
 -                              /* convert T1 = CAST(STRING, X), T2 = CONCAT(T1, Y) to T2 = CONCAT(X,Y) */
 -                              zend_op *src = VAR_SOURCE(opline->op1);
 -                              VAR_UNSET(opline->op1);
 -                              COPY_NODE(opline->op1, src->op1);
 -                              MAKE_NOP(src);
 -                      }
 -                      if ((ZEND_OP2_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
 -                              VAR_SOURCE(opline->op2) &&
 -                              VAR_SOURCE(opline->op2)->opcode == ZEND_CAST &&
 -                              VAR_SOURCE(opline->op2)->extended_value == IS_STRING) {
 -                              /* convert T1 = CAST(STRING, X), T2 = CONCAT(Y, T1) to T2 = CONCAT(Y,X) */
 -                              zend_op *src = VAR_SOURCE(opline->op2);
 -                              VAR_UNSET(opline->op2);
 -                              COPY_NODE(opline->op2, src->op1);
 -                              MAKE_NOP(src);
 -                      }
 -                      if (ZEND_OP1_TYPE(opline) == IS_CONST &&
 -                          Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
 -                          Z_STRLEN(ZEND_OP1_LITERAL(opline)) == 0) {
 -                              /* convert CONCAT('', X) => CAST(STRING, X) */
 -                              literal_dtor(&ZEND_OP1_LITERAL(opline));
 -                              opline->opcode = ZEND_CAST;
 -                              opline->extended_value = IS_STRING;
 -                              COPY_NODE(opline->op1, opline->op2);
 -                              opline->op2_type = IS_UNUSED;
 -                              opline->op2.var = 0;
 -                      } else if (ZEND_OP2_TYPE(opline) == IS_CONST &&
 +
 +                              if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
 +                                      src = VAR_SOURCE(opline->op1);
 +                                      if (src &&
 +                                          src->opcode == ZEND_CAST &&
 +                                          src->extended_value == IS_STRING) {
 +                                              /* convert T1 = CAST(STRING, X), T2 = CONCAT(T1, Y) to T2 = CONCAT(X,Y) */
 +                                              VAR_SOURCE(opline->op1) = NULL;
 +                                              COPY_NODE(opline->op1, src->op1);
 +                                              MAKE_NOP(src);
 +                                      }
 +                  }
 +                              if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
 +                                      src = VAR_SOURCE(opline->op2);
 +                                      if (src &&
 +                                          src->opcode == ZEND_CAST &&
 +                                          src->extended_value == IS_STRING) {
 +                                              /* convert T1 = CAST(STRING, X), T2 = CONCAT(Y, T1) to T2 = CONCAT(Y,X) */
 +                                              zend_op *src = VAR_SOURCE(opline->op2);
 +                                              VAR_SOURCE(opline->op2) = NULL;
 +                                              COPY_NODE(opline->op2, src->op1);
 +                                              MAKE_NOP(src);
 +                                      }
 +                              }
 +                              if (opline->op1_type == IS_CONST &&
 +                                  Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
 +                                  Z_STRLEN(ZEND_OP1_LITERAL(opline)) == 0) {
 +                                      /* convert CONCAT('', X) => CAST(STRING, X) */
 +                                      literal_dtor(&ZEND_OP1_LITERAL(opline));
 +                                      opline->opcode = ZEND_CAST;
 +                                      opline->extended_value = IS_STRING;
 +                                      COPY_NODE(opline->op1, opline->op2);
 +                                      opline->op2_type = IS_UNUSED;
 +                                      opline->op2.var = 0;
 +                              } else if (opline->op2_type == IS_CONST &&
                                   Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
                                   Z_STRLEN(ZEND_OP2_LITERAL(opline)) == 0) {
 -                              /* convert CONCAT(X, '') => CAST(STRING, X) */
 -                              literal_dtor(&ZEND_OP2_LITERAL(opline));
 -                              opline->opcode = ZEND_CAST;
 -                              opline->extended_value = IS_STRING;
 -                              opline->op2_type = IS_UNUSED;
 -                              opline->op2.var = 0;
 -                      } else if (opline->opcode == ZEND_CONCAT &&
 -                                 (opline->op1_type == IS_CONST ||
 -                                  (opline->op1_type == IS_TMP_VAR &&
 -                                   VAR_SOURCE(opline->op1) &&
 -                                   (VAR_SOURCE(opline->op1)->opcode == ZEND_FAST_CONCAT ||
 -                                    VAR_SOURCE(opline->op1)->opcode == ZEND_ROPE_END ||
 -                                    VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CONSTANT))) &&
 -                                 (opline->op2_type == IS_CONST ||
 -                                  (opline->op2_type == IS_TMP_VAR &&
 -                                   VAR_SOURCE(opline->op2) &&
 -                                   (VAR_SOURCE(opline->op2)->opcode == ZEND_FAST_CONCAT ||
 -                                    VAR_SOURCE(opline->op2)->opcode == ZEND_ROPE_END ||
 -                                    VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CONSTANT)))) {
 -                              opline->opcode = ZEND_FAST_CONCAT;
 -                      }
 -              } else if (opline->opcode == ZEND_QM_ASSIGN &&
 -                                      ZEND_OP1_TYPE(opline) == ZEND_RESULT_TYPE(opline) &&
 -                                      ZEND_OP1(opline).var == ZEND_RESULT(opline).var) {
 -                      /* strip T = QM_ASSIGN(T) */
 -                      MAKE_NOP(opline);
 -              } else if (opline->opcode == ZEND_BOOL &&
 -                                      ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
 -                                      VAR_SOURCE(opline->op1) &&
 -                                      (VAR_SOURCE(opline->op1)->opcode == ZEND_IS_EQUAL ||
 -                                      VAR_SOURCE(opline->op1)->opcode == ZEND_IS_NOT_EQUAL ||
 -                                      VAR_SOURCE(opline->op1)->opcode == ZEND_IS_SMALLER ||
 -                                      VAR_SOURCE(opline->op1)->opcode == ZEND_IS_SMALLER_OR_EQUAL ||
 -                                      VAR_SOURCE(opline->op1)->opcode == ZEND_BOOL ||
 -                                      VAR_SOURCE(opline->op1)->opcode == ZEND_IS_IDENTICAL ||
 -                                      VAR_SOURCE(opline->op1)->opcode == ZEND_IS_NOT_IDENTICAL ||
 -                                      VAR_SOURCE(opline->op1)->opcode == ZEND_ISSET_ISEMPTY_VAR ||
 -                                      VAR_SOURCE(opline->op1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ) &&
 -                                      !zend_bitset_in(used_ext, VAR_NUM(ZEND_OP1(opline).var))) {
 -                      /* T = IS_SMALLER(X, Y), T1 = BOOL(T) => T = IS_SMALLER(X, Y), T1 = QM_ASSIGN(T) */
 -                      zend_op *src = VAR_SOURCE(opline->op1);
 -                      COPY_NODE(src->result, opline->result);
 -                      SET_VAR_SOURCE(src);
 -                      MAKE_NOP(opline);
 +                                      /* convert CONCAT(X, '') => CAST(STRING, X) */
 +                                      literal_dtor(&ZEND_OP2_LITERAL(opline));
 +                                      opline->opcode = ZEND_CAST;
 +                                      opline->extended_value = IS_STRING;
 +                                      opline->op2_type = IS_UNUSED;
 +                                      opline->op2.var = 0;
 +                              } else if (opline->opcode == ZEND_CONCAT &&
 +                                         (opline->op1_type == IS_CONST ||
 +                                          (opline->op1_type == IS_TMP_VAR &&
 +                                           VAR_SOURCE(opline->op1) &&
 +                                           (VAR_SOURCE(opline->op1)->opcode == ZEND_FAST_CONCAT ||
 +                                            VAR_SOURCE(opline->op1)->opcode == ZEND_ROPE_END ||
 +                                            VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CONSTANT ||
 +                                            VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CLASS_CONSTANT))) &&
 +                                         (opline->op2_type == IS_CONST ||
 +                                          (opline->op2_type == IS_TMP_VAR &&
 +                                           VAR_SOURCE(opline->op2) &&
 +                                           (VAR_SOURCE(opline->op2)->opcode == ZEND_FAST_CONCAT ||
 +                                            VAR_SOURCE(opline->op2)->opcode == ZEND_ROPE_END ||
 +                                            VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CONSTANT ||
 +                                            VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CLASS_CONSTANT)))) {
 +                                      opline->opcode = ZEND_FAST_CONCAT;
 +                              }
 +                              break;
 +
 +                      case ZEND_ADD:
 +                      case ZEND_SUB:
 +                      case ZEND_MUL:
 +                      case ZEND_DIV:
 +                      case ZEND_MOD:
 +                      case ZEND_SL:
 +                      case ZEND_SR:
 +                      case ZEND_IS_SMALLER:
 +                      case ZEND_IS_SMALLER_OR_EQUAL:
 +                      case ZEND_IS_IDENTICAL:
 +                      case ZEND_IS_NOT_IDENTICAL:
 +                      case ZEND_BOOL_XOR:
 +                      case ZEND_BW_OR:
 +                      case ZEND_BW_AND:
 +                      case ZEND_BW_XOR:
 +                              if (opline->op1_type == IS_CONST &&
 +                                  opline->op2_type == IS_CONST) {
 +                                      /* evaluate constant expressions */
 +                                      binary_op_type binary_op;
 +                                      zval result;
 +                                      int er;
 +
 +optimize_constant_binary_op:
 +                                      binary_op = get_binary_op(opline->opcode);
 +                          if ((opline->opcode == ZEND_DIV || opline->opcode == ZEND_MOD) &&
 +                              zval_get_long(&ZEND_OP2_LITERAL(opline)) == 0) {
 +                                              SET_VAR_SOURCE(opline);
 +                              opline++;
 +                                              continue;
 +                          } else if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR) &&
 +                              zval_get_long(&ZEND_OP2_LITERAL(opline)) < 0) {
 +                                              SET_VAR_SOURCE(opline);
 +                              opline++;
 +                                              continue;
 +                                      }
 +                                      er = EG(error_reporting);
 +                                      EG(error_reporting) = 0;
 +                                      if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
 +                                              literal_dtor(&ZEND_OP1_LITERAL(opline));
 +                                              literal_dtor(&ZEND_OP2_LITERAL(opline));
 +                                              opline->opcode = ZEND_QM_ASSIGN;
 +                                              SET_UNUSED(opline->op2);
 +                                              zend_optimizer_update_op1_const(op_array, opline, &result);
 +                                      }
 +                                      EG(error_reporting) = er;
 +                              }
 +                              break;
 +
 +                      case ZEND_BW_NOT:
 +                              if (opline->op1_type == IS_CONST) {
 +                                      /* evaluate constant unary ops */
 +                                      unary_op_type unary_op;
 +                                      zval result;
 +
 +optimize_const_unary_op:
 +                                      unary_op = get_unary_op(opline->opcode);
 +                                      if (unary_op) {
 +                                              unary_op(&result, &ZEND_OP1_LITERAL(opline));
 +                                              literal_dtor(&ZEND_OP1_LITERAL(opline));
 +                                      } else {
 +                                              /* BOOL */
 +                                              result = ZEND_OP1_LITERAL(opline);
 +                                              convert_to_boolean(&result);
 +                                              ZVAL_NULL(&ZEND_OP1_LITERAL(opline));
 +                                      }
 +                                      opline->opcode = ZEND_QM_ASSIGN;
 +                                      zend_optimizer_update_op1_const(op_array, opline, &result);
 +                              }
 +                              break;
 +
 +                      case ZEND_RETURN:
 +                      case ZEND_EXIT:
 +                              if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
 +                                      src = VAR_SOURCE(opline->op1);
 +                                      if (src && src->opcode == ZEND_QM_ASSIGN) {
 +                                              /* T = QM_ASSIGN(X), RETURN(T) to NOP, RETURN(X) */
 +                                              VAR_SOURCE(opline->op1) = NULL;
 +                                              COPY_NODE(opline->op1, src->op1);
 +                                              MAKE_NOP(src);
 +                                      }
 +                              }
 +                              break;
 +
 +                      case ZEND_QM_ASSIGN:
 +                              if (opline->op1_type == opline->result_type &&
 +                                  opline->op1.var == opline->result.var) {
 +                                      /* strip T = QM_ASSIGN(T) */
 +                                      MAKE_NOP(opline);
 +                              }
 +                              break;
                }
 +
                /* get variable source */
 -              if (RESULT_USED(opline)) {
 +              if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
                        SET_VAR_SOURCE(opline);
                }
 -              if (opline->opcode != ZEND_NOP) {
 -                      last_op = opline;
 -              }
                opline++;
        }