Make QM_ASSIGN, JMP_SET and CAST return IS_TMP_VAR.

This commit is contained in:
Dmitry Stogov 2014-09-24 01:57:40 +04:00
parent e8612b72ee
commit 58a41cf795
4 changed files with 53 additions and 87 deletions

View File

@ -483,8 +483,7 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
&& opline->result.var == op1->u.op.var) {
if (opline->opcode == ZEND_FETCH_R ||
opline->opcode == ZEND_FETCH_DIM_R ||
opline->opcode == ZEND_FETCH_OBJ_R ||
opline->opcode == ZEND_QM_ASSIGN) {
opline->opcode == ZEND_FETCH_OBJ_R) {
/* It's very rare and useless case. It's better to use
additional FREE opcode and simplify the FETCH handlers
their selves */
@ -1708,7 +1707,9 @@ static zend_op *zend_emit_op_tmp(znode *result, zend_uchar opcode, znode *op1, z
SET_NODE(opline->op2, op2);
}
zend_make_tmp_result(result, opline TSRMLS_CC);
if (result) {
zend_make_tmp_result(result, opline TSRMLS_CC);
}
return opline;
}
@ -5259,7 +5260,7 @@ void zend_compile_cast(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
opline = zend_emit_op(result, ZEND_CAST, &expr_node, NULL TSRMLS_CC);
opline = zend_emit_op_tmp(result, ZEND_CAST, &expr_node, NULL TSRMLS_CC);
opline->extended_value = ast->attr;
}
/* }}} */
@ -5278,13 +5279,13 @@ static void zend_compile_shorthand_conditional(znode *result, zend_ast *ast TSRM
zend_compile_expr(&cond_node, cond_ast TSRMLS_CC);
opnum_jmp_set = get_next_op_number(CG(active_op_array));
zend_emit_op(result, ZEND_JMP_SET, &cond_node, NULL TSRMLS_CC);
zend_emit_op_tmp(result, ZEND_JMP_SET, &cond_node, NULL TSRMLS_CC);
zend_compile_expr(&false_node, false_ast TSRMLS_CC);
opline_jmp_set = &CG(active_op_array)->opcodes[opnum_jmp_set];
opline_jmp_set->op2.opline_num = get_next_op_number(CG(active_op_array)) + 1;
opline_qm_assign = zend_emit_op(NULL, ZEND_QM_ASSIGN, &false_node, NULL TSRMLS_CC);
opline_qm_assign = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &false_node, NULL TSRMLS_CC);
SET_NODE(opline_qm_assign->result, result);
}
/* }}} */
@ -5311,7 +5312,7 @@ void zend_compile_conditional(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
zend_compile_expr(&true_node, true_ast TSRMLS_CC);
opnum_qm_assign1 = get_next_op_number(CG(active_op_array));
zend_emit_op(result, ZEND_QM_ASSIGN, &true_node, NULL TSRMLS_CC);
zend_emit_op_tmp(result, ZEND_QM_ASSIGN, &true_node, NULL TSRMLS_CC);
opnum_jmp = zend_emit_jump(0 TSRMLS_CC);

View File

@ -91,7 +91,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
literal_dtor(&ZEND_OP2_LITERAL(opline));
MAKE_NOP(opline);
zend_optimizer_replace_tmp_by_const(op_array, opline + 1, tv, &result TSRMLS_CC);
zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result TSRMLS_CC);
}
break;
@ -101,6 +101,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
opline->extended_value != IS_OBJECT &&
opline->extended_value != IS_RESOURCE) {
/* cast of constant operand */
zend_uchar type = opline->result_type;
uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */
zval res;
res = ZEND_OP1_LITERAL(opline);
@ -126,11 +127,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
literal_dtor(&ZEND_OP1_LITERAL(opline));
MAKE_NOP(opline);
if (opline->result_type == IS_TMP_VAR) {
zend_optimizer_replace_tmp_by_const(op_array, opline + 1, tv, &res TSRMLS_CC);
} else /* if (opline->result_type == IS_VAR) */ {
zend_optimizer_replace_var_by_const(op_array, opline + 1, tv, &res TSRMLS_CC);
}
zend_optimizer_replace_by_const(op_array, opline + 1, type, tv, &res TSRMLS_CC);
} else if (opline->extended_value == _IS_BOOL) {
/* T = CAST(X, IS_BOOL) => T = BOOL(X) */
opline->opcode = ZEND_BOOL;
@ -157,7 +154,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
literal_dtor(&ZEND_OP1_LITERAL(opline));
MAKE_NOP(opline);
zend_optimizer_replace_tmp_by_const(op_array, opline + 1, tv, &result TSRMLS_CC);
zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result TSRMLS_CC);
}
break;
@ -251,7 +248,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
literal_dtor(&ZEND_OP2_LITERAL(opline));
MAKE_NOP(opline);
zend_optimizer_replace_tmp_by_const(op_array, opline, tv, offset TSRMLS_CC);
zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, offset TSRMLS_CC);
}
EG(current_execute_data) = orig_execute_data;
break;
@ -271,7 +268,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
}
literal_dtor(&ZEND_OP2_LITERAL(opline));
MAKE_NOP(opline);
zend_optimizer_replace_tmp_by_const(op_array, opline, tv, &c TSRMLS_CC);
zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c TSRMLS_CC);
}
/* class constant */
@ -332,7 +329,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
}
literal_dtor(&ZEND_OP2_LITERAL(opline));
MAKE_NOP(opline);
zend_optimizer_replace_tmp_by_const(op_array, opline, tv, &t TSRMLS_CC);
zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &t TSRMLS_CC);
}
}
}
@ -388,7 +385,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
func->module->type == MODULE_PERSISTENT) {
zval t;
ZVAL_BOOL(&t, 1);
if (zend_optimizer_replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
if (zend_optimizer_replace_by_const(op_array, opline + 3, IS_VAR, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
literal_dtor(&ZEND_OP2_LITERAL(opline));
MAKE_NOP(opline);
literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
@ -421,7 +418,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
}
}
if (zend_optimizer_replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
if (zend_optimizer_replace_by_const(op_array, opline + 3, IS_VAR, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
literal_dtor(&ZEND_OP2_LITERAL(opline));
MAKE_NOP(opline);
literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
@ -436,7 +433,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline + 1)), &t, 0 TSRMLS_CC)) {
ZVAL_BOOL(&t, 1);
if (zend_optimizer_replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
if (zend_optimizer_replace_by_const(op_array, opline + 3, IS_VAR, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
literal_dtor(&ZEND_OP2_LITERAL(opline));
MAKE_NOP(opline);
literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
@ -450,7 +447,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
zval t;
if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline + 1)), &t, 1 TSRMLS_CC)) {
if (zend_optimizer_replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
if (zend_optimizer_replace_by_const(op_array, opline + 3, IS_VAR, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
literal_dtor(&ZEND_OP2_LITERAL(opline));
MAKE_NOP(opline);
literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
@ -465,7 +462,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
zval t;
ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)));
if (zend_optimizer_replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
if (zend_optimizer_replace_by_const(op_array, opline + 3, IS_VAR, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
literal_dtor(&ZEND_OP2_LITERAL(opline));
MAKE_NOP(opline);
literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
@ -481,7 +478,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
zval t;
ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline)));
zend_optimizer_replace_tmp_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC);
zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, ZEND_RESULT(opline).var, &t TSRMLS_CC);
literal_dtor(&ZEND_OP1_LITERAL(opline));
MAKE_NOP(opline);
}
@ -494,7 +491,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
break;
}
ZVAL_TRUE(&c);
zend_optimizer_replace_tmp_by_const(op_array, opline, tv, &c TSRMLS_CC);
zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c TSRMLS_CC);
literal_dtor(&ZEND_OP1_LITERAL(opline));
MAKE_NOP(opline);
}

View File

@ -262,15 +262,16 @@ check_numeric:
}
}
int zend_optimizer_replace_var_by_const(zend_op_array *op_array,
zend_op *opline,
uint32_t var,
zval *val TSRMLS_DC)
int zend_optimizer_replace_by_const(zend_op_array *op_array,
zend_op *opline,
zend_uchar type,
uint32_t var,
zval *val TSRMLS_DC)
{
zend_op *end = op_array->opcodes + op_array->last;
while (opline < end) {
if (ZEND_OP1_TYPE(opline) == IS_VAR &&
if (ZEND_OP1_TYPE(opline) == type &&
ZEND_OP1(opline).var == var) {
switch (opline->opcode) {
case ZEND_FETCH_DIM_W:
@ -292,6 +293,25 @@ int zend_optimizer_replace_var_by_const(zend_op_array *op_array,
opline->opcode = ZEND_SEND_VAL;
}
break;
/* In most cases IS_TMP_VAR operand may be used only once.
* The operands are usually destroyed by the opcode handler.
* ZEND_CASE is an exception, that keeps operand unchanged,
* and allows its reuse. The number of ZEND_CASE instructions
* usually terminated by ZEND_FREE that finally kills the value.
*/
case ZEND_CASE: {
zval old_val;
ZVAL_COPY_VALUE(&old_val, val);
zval_copy_ctor(val);
zend_optimizer_update_op1_const(op_array, opline, val TSRMLS_CC);
zval_dtor(&old_val);
opline++;
continue;
}
case ZEND_FREE:
MAKE_NOP(opline);
zval_dtor(val);
return 1;
default:
break;
}
@ -299,7 +319,7 @@ int zend_optimizer_replace_var_by_const(zend_op_array *op_array,
break;
}
if (ZEND_OP2_TYPE(opline) == IS_VAR &&
if (ZEND_OP2_TYPE(opline) == type &&
ZEND_OP2(opline).var == var) {
switch (opline->opcode) {
case ZEND_ASSIGN_REF:
@ -316,55 +336,6 @@ int zend_optimizer_replace_var_by_const(zend_op_array *op_array,
return 1;
}
void zend_optimizer_replace_tmp_by_const(zend_op_array *op_array,
zend_op *opline,
uint32_t var,
zval *val
TSRMLS_DC)
{
zend_op *end = op_array->opcodes + op_array->last;
while (opline < end) {
if (ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
ZEND_OP1(opline).var == var) {
/* In most cases IS_TMP_VAR operand may be used only once.
* The operands are usually destroyed by the opcode handler.
* ZEND_CASE is an exception, that keeps operand unchanged,
* and allows its reuse. The number of ZEND_CASE instructions
* usually terminated by ZEND_FREE that finally kills the value.
*/
if (opline->opcode == ZEND_CASE) {
zval old_val;
ZVAL_COPY_VALUE(&old_val, val);
zval_copy_ctor(val);
zend_optimizer_update_op1_const(op_array, opline, val TSRMLS_CC);
ZVAL_COPY_VALUE(val, &old_val);
} else if (opline->opcode == ZEND_FREE) {
MAKE_NOP(opline);
break;
} else {
zend_optimizer_update_op1_const(op_array, opline, val TSRMLS_CC);
val = NULL;
break;
}
}
if (ZEND_OP2_TYPE(opline) == IS_TMP_VAR &&
ZEND_OP2(opline).var == var) {
zend_optimizer_update_op2_const(op_array, opline, val TSRMLS_CC);
/* TMP_VAR may be used only once */
val = NULL;
break;
}
opline++;
}
if (val) {
zval_dtor(val);
}
}
static void zend_optimize(zend_op_array *op_array,
zend_optimizer_ctx *ctx TSRMLS_DC)
{

View File

@ -112,14 +112,11 @@ void zend_optimizer_update_op1_const(zend_op_array *op_array,
void zend_optimizer_update_op2_const(zend_op_array *op_array,
zend_op *opline,
zval *val TSRMLS_DC);
int zend_optimizer_replace_var_by_const(zend_op_array *op_array,
zend_op *opline,
uint32_t var,
zval *val TSRMLS_DC);
void zend_optimizer_replace_tmp_by_const(zend_op_array *op_array,
zend_op *opline,
uint32_t var,
zval *val TSRMLS_DC);
int zend_optimizer_replace_by_const(zend_op_array *op_array,
zend_op *opline,
zend_uchar type,
uint32_t var,
zval *val TSRMLS_DC);
void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRMLS_DC);
void zend_optimizer_pass2(zend_op_array *op_array TSRMLS_DC);