root/ext/opcache/Optimizer/pass2.c

/* [<][>][^][v][top][bottom][index][help] */
   1 /* pass 2:
   2  * - convert non-numeric constants to numeric constants in numeric operators
   3  * - optimize constant conditional JMPs
   4  * - optimize static BRKs and CONTs
   5  */
   6 
   7 if (ZEND_OPTIMIZER_PASS_2 & OPTIMIZATION_LEVEL) {
   8         zend_op *opline;
   9         zend_op *end = op_array->opcodes + op_array->last;
  10 
  11         opline = op_array->opcodes;
  12         while (opline < end) {
  13                 switch (opline->opcode) {
  14                         case ZEND_ADD:
  15                         case ZEND_SUB:
  16                         case ZEND_MUL:
  17                         case ZEND_DIV:
  18                                 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
  19                                         if (ZEND_OP1_LITERAL(opline).type == IS_STRING) {
  20                                                 convert_scalar_to_number(&ZEND_OP1_LITERAL(opline) TSRMLS_CC);
  21                                         }
  22                                 }
  23                                 /* break missing *intentionally* - the assign_op's may only optimize op2 */
  24                         case ZEND_ASSIGN_ADD:
  25                         case ZEND_ASSIGN_SUB:
  26                         case ZEND_ASSIGN_MUL:
  27                         case ZEND_ASSIGN_DIV:
  28                                 if (opline->extended_value != 0) {
  29                                         /* object tristate op - don't attempt to optimize it! */
  30                                         break;
  31                                 }
  32                                 if (ZEND_OP2_TYPE(opline) == IS_CONST) {
  33                                         if (ZEND_OP2_LITERAL(opline).type == IS_STRING) {
  34                                                 convert_scalar_to_number(&ZEND_OP2_LITERAL(opline) TSRMLS_CC);
  35                                         }
  36                                 }
  37                                 break;
  38 
  39                         case ZEND_MOD:
  40                         case ZEND_SL:
  41                         case ZEND_SR:
  42                                 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
  43                                         if (ZEND_OP1_LITERAL(opline).type != IS_LONG) {
  44                                                 convert_to_long(&ZEND_OP1_LITERAL(opline));
  45                                         }
  46                                 }
  47                                 /* break missing *intentionally - the assign_op's may only optimize op2 */
  48                         case ZEND_ASSIGN_MOD:
  49                         case ZEND_ASSIGN_SL:
  50                         case ZEND_ASSIGN_SR:
  51                                 if (opline->extended_value != 0) {
  52                                         /* object tristate op - don't attempt to optimize it! */
  53                                         break;
  54                                 }
  55                                 if (ZEND_OP2_TYPE(opline) == IS_CONST) {
  56                                         if (ZEND_OP2_LITERAL(opline).type != IS_LONG) {
  57                                                 convert_to_long(&ZEND_OP2_LITERAL(opline));
  58                                         }
  59                                 }
  60                                 break;
  61 
  62                         case ZEND_CONCAT:
  63                                 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
  64                                         if (ZEND_OP1_LITERAL(opline).type != IS_STRING) {
  65                                                 convert_to_string(&ZEND_OP1_LITERAL(opline));
  66                                         }
  67                                 }
  68                                 /* break missing *intentionally - the assign_op's may only optimize op2 */
  69                         case ZEND_ASSIGN_CONCAT:
  70                                 if (opline->extended_value != 0) {
  71                                         /* object tristate op - don't attempt to optimize it! */
  72                                         break;
  73                                 }
  74                                 if (ZEND_OP2_TYPE(opline) == IS_CONST) {
  75                                         if (ZEND_OP2_LITERAL(opline).type != IS_STRING) {
  76                                                 convert_to_string(&ZEND_OP2_LITERAL(opline));
  77                                         }
  78                                 }
  79                                 break;
  80 
  81                         case ZEND_JMPZ_EX:
  82                         case ZEND_JMPNZ_EX:
  83                                 /* convert Ti = JMPZ_EX(Ti, L) to JMPZ(Ti, L) */
  84                                 if (0 && /* FIXME: temporary disable unsafe pattern */
  85                                     ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
  86                                     ZEND_RESULT_TYPE(opline) == IS_TMP_VAR &&
  87                                     ZEND_OP1(opline).var == ZEND_RESULT(opline).var) {
  88                                         opline->opcode -= 3;
  89                                 /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
  90                                    in case we know it wouldn't jump */
  91                                 } else if (ZEND_OP1_TYPE(opline) == IS_CONST) {
  92                                         int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
  93                                         if (opline->opcode == ZEND_JMPZ_EX) {
  94                                                 should_jmp = !should_jmp;
  95                                         }
  96                                         if (!should_jmp) {
  97                                                 opline->opcode = ZEND_QM_ASSIGN;
  98                                                 SET_UNUSED(opline->op2);
  99                                         }
 100                                 }
 101                                 break;
 102 
 103                         case ZEND_JMPZ:
 104                         case ZEND_JMPNZ:
 105                                 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
 106                                         int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
 107 
 108                                         if (opline->opcode == ZEND_JMPZ) {
 109                                                 should_jmp = !should_jmp;
 110                                         }
 111                                         literal_dtor(&ZEND_OP1_LITERAL(opline));
 112                                         ZEND_OP1_TYPE(opline) = IS_UNUSED;
 113                                         if (should_jmp) {
 114                                                 opline->opcode = ZEND_JMP;
 115                                                 COPY_NODE(opline->op1, opline->op2);
 116                                         } else {
 117                                                 MAKE_NOP(opline);
 118                                         }
 119                                         break;
 120                                 }
 121                                 if ((opline + 1)->opcode == ZEND_JMP) {
 122                                         /* JMPZ(X, L1), JMP(L2) => JMPZNZ(X, L1, L2) */
 123                                         /* JMPNZ(X, L1), JMP(L2) => JMPZNZ(X, L2, L1) */
 124                                         if (ZEND_OP2(opline).opline_num == ZEND_OP1(opline + 1).opline_num) {
 125                                                 /* JMPZ(X, L1), JMP(L1) => NOP, JMP(L1) */
 126                                                 MAKE_NOP(opline);
 127                                         } else {
 128                                                 if (opline->opcode == ZEND_JMPZ) {
 129                                                         opline->extended_value = ZEND_OP1(opline + 1).opline_num;
 130                                                 } else {
 131                                                         opline->extended_value = ZEND_OP2(opline).opline_num;
 132                                                         COPY_NODE(opline->op2, (opline + 1)->op1);
 133                                                 }
 134                                                 opline->opcode = ZEND_JMPZNZ;
 135                                         }
 136                                 }
 137                                 break;
 138 
 139                         case ZEND_JMPZNZ:
 140                                 if (ZEND_OP1_TYPE(opline) == IS_CONST) {
 141                                         int opline_num;
 142 
 143                                         if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
 144                                                 opline_num = opline->extended_value; /* JMPNZ */
 145                                         } else {
 146                                                 opline_num = ZEND_OP2(opline).opline_num; /* JMPZ */
 147                                         }
 148                                         literal_dtor(&ZEND_OP1_LITERAL(opline));
 149                                         ZEND_OP1(opline).opline_num = opline_num;
 150                                         ZEND_OP1_TYPE(opline) = IS_UNUSED;
 151                                         opline->opcode = ZEND_JMP;
 152                                 }
 153                                 break;
 154 
 155                         case ZEND_BRK:
 156                         case ZEND_CONT:
 157                                 {
 158                                     zend_brk_cont_element *jmp_to;
 159                                         int array_offset;
 160                                         int nest_levels;
 161                                         int dont_optimize = 0;
 162 
 163                                         if (ZEND_OP2_TYPE(opline) != IS_CONST) {
 164                                                 break;
 165                                         }
 166                                         convert_to_long(&ZEND_OP2_LITERAL(opline));
 167                                         nest_levels = ZEND_OP2_LITERAL(opline).value.lval;
 168 
 169                                         array_offset = ZEND_OP1(opline).opline_num;
 170                                         while (1) {
 171                                                 if (array_offset == -1) {
 172                                                         dont_optimize = 1; /* don't optimize this bogus break/continue, let the executor shout */
 173                                                         break;
 174                                                 }
 175                                                 jmp_to = &op_array->brk_cont_array[array_offset];
 176                                                 array_offset = jmp_to->parent;
 177                                                 if (--nest_levels > 0) {
 178                                                         if (op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE ||
 179                                                             op_array->opcodes[jmp_to->brk].opcode == ZEND_SWITCH_FREE
 180                                                         ) {
 181                                                                 dont_optimize = 1;
 182                                                                 break;
 183                                                         }
 184                                                 } else {
 185                                                         break;
 186                                                 }
 187                                         }
 188 
 189                                         if (dont_optimize) {
 190                                                 break;
 191                                         }
 192 
 193                                         /* optimize - convert to a JMP */
 194                                         switch (opline->opcode) {
 195                                                 case ZEND_BRK:
 196                                                         MAKE_NOP(opline);
 197                                                         ZEND_OP1(opline).opline_num = jmp_to->brk;
 198                                                         break;
 199                                                 case ZEND_CONT:
 200                                                         MAKE_NOP(opline);
 201                                                         ZEND_OP1(opline).opline_num = jmp_to->cont;
 202                                                         break;
 203                                         }
 204                                         opline->opcode = ZEND_JMP;
 205                                         /* MAKE_NOP() already set op1 and op2 to IS_UNUSED */
 206                                 }
 207                                 break;
 208                 }
 209                 opline++;
 210         }
 211 }

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