php-src/ext/opcache/Optimizer/pass2.c

188 lines
6.1 KiB
C
Raw Normal View History

2014-08-15 08:47:54 +00:00
/*
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
2015-01-15 15:27:30 +00:00
| Copyright (c) 1998-2015 The PHP Group |
2014-08-15 08:47:54 +00:00
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans <andi@zend.com> |
| Zeev Suraski <zeev@zend.com> |
| Stanislav Malyshev <stas@zend.com> |
| Dmitry Stogov <dmitry@zend.com> |
+----------------------------------------------------------------------+
*/
2013-02-13 12:26:47 +00:00
/* pass 2:
* - convert non-numeric constants to numeric constants in numeric operators
* - optimize constant conditional JMPs
* - optimize static BRKs and CONTs
*/
#include "php.h"
#include "Optimizer/zend_optimizer.h"
#include "Optimizer/zend_optimizer_internal.h"
#include "zend_API.h"
#include "zend_constants.h"
#include "zend_execute.h"
#include "zend_vm.h"
2014-12-13 22:06:14 +00:00
void zend_optimizer_pass2(zend_op_array *op_array)
{
2013-02-13 12:26:47 +00:00
zend_op *opline;
2013-02-22 06:56:05 +00:00
zend_op *end = op_array->opcodes + op_array->last;
2013-02-13 12:26:47 +00:00
opline = op_array->opcodes;
2013-02-22 06:56:05 +00:00
while (opline < end) {
2013-02-13 12:26:47 +00:00
switch (opline->opcode) {
case ZEND_ADD:
case ZEND_SUB:
case ZEND_MUL:
case ZEND_DIV:
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
if (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
2014-12-13 22:06:14 +00:00
convert_scalar_to_number(&ZEND_OP1_LITERAL(opline));
2013-02-13 12:26:47 +00:00
}
}
/* 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:
2013-02-22 06:56:05 +00:00
if (opline->extended_value != 0) {
2013-02-13 12:26:47 +00:00
/* object tristate op - don't attempt to optimize it! */
break;
}
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
2014-12-13 22:06:14 +00:00
convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
2013-02-13 12:26:47 +00:00
}
}
break;
case ZEND_MOD:
case ZEND_SL:
case ZEND_SR:
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
2014-08-25 17:24:55 +00:00
if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_LONG) {
2014-08-25 19:51:49 +00:00
convert_to_long(&ZEND_OP1_LITERAL(opline));
2013-02-13 12:26:47 +00:00
}
}
/* break missing *intentionally - the assign_op's may only optimize op2 */
case ZEND_ASSIGN_MOD:
case ZEND_ASSIGN_SL:
case ZEND_ASSIGN_SR:
2013-02-22 06:56:05 +00:00
if (opline->extended_value != 0) {
2013-02-13 12:26:47 +00:00
/* object tristate op - don't attempt to optimize it! */
break;
}
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
2014-08-25 17:24:55 +00:00
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
2014-08-25 19:51:49 +00:00
convert_to_long(&ZEND_OP2_LITERAL(opline));
2013-02-13 12:26:47 +00:00
}
}
break;
2013-02-22 06:56:05 +00:00
2013-02-13 12:26:47 +00:00
case ZEND_CONCAT:
case ZEND_FAST_CONCAT:
2013-02-13 12:26:47 +00:00
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
2013-02-13 12:26:47 +00:00
convert_to_string(&ZEND_OP1_LITERAL(opline));
}
}
/* break missing *intentionally - the assign_op's may only optimize op2 */
case ZEND_ASSIGN_CONCAT:
2013-02-22 06:56:05 +00:00
if (opline->extended_value != 0) {
2013-02-13 12:26:47 +00:00
/* object tristate op - don't attempt to optimize it! */
break;
}
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
2013-02-13 12:26:47 +00:00
convert_to_string(&ZEND_OP2_LITERAL(opline));
}
}
break;
2013-02-22 06:56:05 +00:00
2013-02-13 12:26:47 +00:00
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
/* convert Ti = JMPZ_EX(Ti, L) to JMPZ(Ti, L) */
2013-03-11 18:49:05 +00:00
if (0 && /* FIXME: temporary disable unsafe pattern */
2013-02-14 09:06:30 +00:00
ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
2013-02-13 12:26:47 +00:00
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) {
2014-12-13 22:06:14 +00:00
int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
2013-02-13 12:26:47 +00:00
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) {
2014-12-13 22:06:14 +00:00
int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
2013-02-13 12:26:47 +00:00
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;
}
2013-02-22 06:56:05 +00:00
if ((opline + 1)->opcode == ZEND_JMP) {
2013-02-13 12:26:47 +00:00
/* JMPZ(X, L1), JMP(L2) => JMPZNZ(X, L1, L2) */
/* JMPNZ(X, L1), JMP(L2) => JMPZNZ(X, L2, L1) */
2013-02-22 06:56:05 +00:00
if (ZEND_OP2(opline).opline_num == ZEND_OP1(opline + 1).opline_num) {
2013-02-13 12:26:47 +00:00
/* JMPZ(X, L1), JMP(L1) => NOP, JMP(L1) */
MAKE_NOP(opline);
} else {
if (opline->opcode == ZEND_JMPZ) {
2013-02-22 06:56:05 +00:00
opline->extended_value = ZEND_OP1(opline + 1).opline_num;
2013-02-13 12:26:47 +00:00
} else {
opline->extended_value = ZEND_OP2(opline).opline_num;
2013-02-22 06:56:05 +00:00
COPY_NODE(opline->op2, (opline + 1)->op1);
2013-02-13 12:26:47 +00:00
}
opline->opcode = ZEND_JMPZNZ;
}
}
break;
case ZEND_JMPZNZ:
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
int opline_num;
2014-12-13 22:06:14 +00:00
if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
2013-02-13 12:26:47 +00:00
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;
}
opline++;
}
}