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 } 212