root/ext/opcache/Optimizer/block_pass.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_optimizer_get_persistent_constant
  2. print_block
  3. find_code_blocks
  4. replace_source
  5. del_source
  6. delete_code_block
  7. zend_access_path
  8. zend_rebuild_access_path
  9. strip_nop
  10. zend_optimize_block
  11. assemble_code_blocks
  12. zend_jmp_optimization
  13. zend_t_usage
  14. optimize_cfg

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

/* [<][>][^][v][top][bottom][index][help] */