123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- /* pass 2:
- * - convert non-numeric constants to numeric constants in numeric operators
- * - optimize constant conditional JMPs
- * - optimize static BRKs and CONTs
- */
- if (ZEND_OPTIMIZER_PASS_2 & OPTIMIZATION_LEVEL) {
- zend_op *opline;
- zend_op *end = op_array->opcodes + op_array->last;
- opline = op_array->opcodes;
- while (opline < end) {
- switch (opline->opcode) {
- case ZEND_ADD:
- case ZEND_SUB:
- case ZEND_MUL:
- case ZEND_DIV:
- if (ZEND_OP1_TYPE(opline) == IS_CONST) {
- if (ZEND_OP1_LITERAL(opline).type == IS_STRING) {
- convert_scalar_to_number(&ZEND_OP1_LITERAL(opline) TSRMLS_CC);
- }
- }
- /* break missing *intentionally* - the assign_op's may only optimize op2 */
- case ZEND_ASSIGN_ADD:
- case ZEND_ASSIGN_SUB:
- case ZEND_ASSIGN_MUL:
- case ZEND_ASSIGN_DIV:
- if (opline->extended_value != 0) {
- /* object tristate op - don't attempt to optimize it! */
- break;
- }
- if (ZEND_OP2_TYPE(opline) == IS_CONST) {
- if (ZEND_OP2_LITERAL(opline).type == IS_STRING) {
- convert_scalar_to_number(&ZEND_OP2_LITERAL(opline) TSRMLS_CC);
- }
- }
- break;
- case ZEND_MOD:
- case ZEND_SL:
- case ZEND_SR:
- if (ZEND_OP1_TYPE(opline) == IS_CONST) {
- if (ZEND_OP1_LITERAL(opline).type != IS_LONG) {
- convert_to_long(&ZEND_OP1_LITERAL(opline));
- }
- }
- /* break missing *intentionally - the assign_op's may only optimize op2 */
- case ZEND_ASSIGN_MOD:
- case ZEND_ASSIGN_SL:
- case ZEND_ASSIGN_SR:
- if (opline->extended_value != 0) {
- /* object tristate op - don't attempt to optimize it! */
- break;
- }
- if (ZEND_OP2_TYPE(opline) == IS_CONST) {
- if (ZEND_OP2_LITERAL(opline).type != IS_LONG) {
- convert_to_long(&ZEND_OP2_LITERAL(opline));
- }
- }
- break;
- case ZEND_CONCAT:
- if (ZEND_OP1_TYPE(opline) == IS_CONST) {
- if (ZEND_OP1_LITERAL(opline).type != IS_STRING) {
- convert_to_string(&ZEND_OP1_LITERAL(opline));
- }
- }
- /* break missing *intentionally - the assign_op's may only optimize op2 */
- case ZEND_ASSIGN_CONCAT:
- if (opline->extended_value != 0) {
- /* object tristate op - don't attempt to optimize it! */
- break;
- }
- if (ZEND_OP2_TYPE(opline) == IS_CONST) {
- if (ZEND_OP2_LITERAL(opline).type != IS_STRING) {
- convert_to_string(&ZEND_OP2_LITERAL(opline));
- }
- }
- break;
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- /* convert Ti = JMPZ_EX(Ti, L) to JMPZ(Ti, L) */
- if (0 && /* FIXME: temporary disable unsafe pattern */
- ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
- ZEND_RESULT_TYPE(opline) == IS_TMP_VAR &&
- ZEND_OP1(opline).var == ZEND_RESULT(opline).var) {
- opline->opcode -= 3;
- /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
- in case we know it wouldn't jump */
- } else if (ZEND_OP1_TYPE(opline) == IS_CONST) {
- int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
- if (opline->opcode == ZEND_JMPZ_EX) {
- should_jmp = !should_jmp;
- }
- if (!should_jmp) {
- opline->opcode = ZEND_QM_ASSIGN;
- SET_UNUSED(opline->op2);
- }
- }
- break;
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- if (ZEND_OP1_TYPE(opline) == IS_CONST) {
- int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
- if (opline->opcode == ZEND_JMPZ) {
- should_jmp = !should_jmp;
- }
- literal_dtor(&ZEND_OP1_LITERAL(opline));
- ZEND_OP1_TYPE(opline) = IS_UNUSED;
- if (should_jmp) {
- opline->opcode = ZEND_JMP;
- COPY_NODE(opline->op1, opline->op2);
- } else {
- MAKE_NOP(opline);
- }
- break;
- }
- if ((opline + 1)->opcode == ZEND_JMP) {
- /* JMPZ(X, L1), JMP(L2) => JMPZNZ(X, L1, L2) */
- /* JMPNZ(X, L1), JMP(L2) => JMPZNZ(X, L2, L1) */
- if (ZEND_OP2(opline).opline_num == ZEND_OP1(opline + 1).opline_num) {
- /* JMPZ(X, L1), JMP(L1) => NOP, JMP(L1) */
- MAKE_NOP(opline);
- } else {
- if (opline->opcode == ZEND_JMPZ) {
- opline->extended_value = ZEND_OP1(opline + 1).opline_num;
- } else {
- opline->extended_value = ZEND_OP2(opline).opline_num;
- COPY_NODE(opline->op2, (opline + 1)->op1);
- }
- opline->opcode = ZEND_JMPZNZ;
- }
- }
- break;
- case ZEND_JMPZNZ:
- if (ZEND_OP1_TYPE(opline) == IS_CONST) {
- int opline_num;
- if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
- opline_num = opline->extended_value; /* JMPNZ */
- } else {
- opline_num = ZEND_OP2(opline).opline_num; /* JMPZ */
- }
- literal_dtor(&ZEND_OP1_LITERAL(opline));
- ZEND_OP1(opline).opline_num = opline_num;
- ZEND_OP1_TYPE(opline) = IS_UNUSED;
- opline->opcode = ZEND_JMP;
- }
- break;
- case ZEND_BRK:
- case ZEND_CONT:
- {
- zend_brk_cont_element *jmp_to;
- int array_offset;
- int nest_levels;
- int dont_optimize = 0;
- if (ZEND_OP2_TYPE(opline) != IS_CONST) {
- break;
- }
- convert_to_long(&ZEND_OP2_LITERAL(opline));
- nest_levels = ZEND_OP2_LITERAL(opline).value.lval;
- array_offset = ZEND_OP1(opline).opline_num;
- while (1) {
- if (array_offset == -1) {
- dont_optimize = 1; /* don't optimize this bogus break/continue, let the executor shout */
- break;
- }
- jmp_to = &op_array->brk_cont_array[array_offset];
- array_offset = jmp_to->parent;
- if (--nest_levels > 0) {
- if (op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE ||
- op_array->opcodes[jmp_to->brk].opcode == ZEND_SWITCH_FREE
- ) {
- dont_optimize = 1;
- break;
- }
- } else {
- break;
- }
- }
- if (dont_optimize) {
- break;
- }
- /* optimize - convert to a JMP */
- switch (opline->opcode) {
- case ZEND_BRK:
- MAKE_NOP(opline);
- ZEND_OP1(opline).opline_num = jmp_to->brk;
- break;
- case ZEND_CONT:
- MAKE_NOP(opline);
- ZEND_OP1(opline).opline_num = jmp_to->cont;
- break;
- }
- opline->opcode = ZEND_JMP;
- /* MAKE_NOP() already set op1 and op2 to IS_UNUSED */
- }
- break;
- }
- opline++;
- }
- }
|