Check if instruction may throw exception only for instructions without known side effects.

Always disable removing ASSIGN and UNSET_VAR that may throw.
This commit is contained in:
Dmitry Stogov 2017-07-12 13:07:14 +03:00
parent c5aa1f47cd
commit 4b64dbb30d
2 changed files with 9 additions and 18 deletions

View file

@ -69,13 +69,9 @@ static inline zend_bool is_bad_mod(const zend_ssa *ssa, int use, int def) {
} }
static inline zend_bool may_have_side_effects( static inline zend_bool may_have_side_effects(
const context *ctx, const zend_op *opline, const zend_ssa_op *ssa_op) { zend_op_array *op_array, zend_ssa *ssa,
zend_op_array *op_array = ctx->op_array; const zend_op *opline, const zend_ssa_op *ssa_op,
zend_ssa *ssa = ctx->ssa; zend_bool reorder_dtor_effects) {
if (zend_may_throw(opline, op_array, ssa)) {
return 1;
}
switch (opline->opcode) { switch (opline->opcode) {
case ZEND_NOP: case ZEND_NOP:
case ZEND_IS_IDENTICAL: case ZEND_IS_IDENTICAL:
@ -154,15 +150,10 @@ static inline zend_bool may_have_side_effects(
return 1; return 1;
case ZEND_ASSIGN: case ZEND_ASSIGN:
{ {
uint32_t t1 = OP1_INFO();
if (is_bad_mod(ssa, ssa_op->op1_use, ssa_op->op1_def)) { if (is_bad_mod(ssa, ssa_op->op1_use, ssa_op->op1_def)) {
return 1; return 1;
} }
if (!ctx->reorder_dtor_effects) { if (!reorder_dtor_effects) {
if (t1 & MAY_HAVE_DTOR) {
/* DCE might extend lifetime */
return 1;
}
if (opline->op2_type != IS_CONST && (OP2_INFO() & MAY_HAVE_DTOR)) { if (opline->op2_type != IS_CONST && (OP2_INFO() & MAY_HAVE_DTOR)) {
/* DCE might shorten lifetime */ /* DCE might shorten lifetime */
return 1; return 1;
@ -183,10 +174,6 @@ static inline zend_bool may_have_side_effects(
* is a reference, because unset breaks references. */ * is a reference, because unset breaks references. */
return 1; return 1;
} }
if (!ctx->reorder_dtor_effects && (t1 & MAY_HAVE_DTOR)) {
/* DCE might extend lifetime */
return 1;
}
return 0; return 0;
} }
case ZEND_PRE_INC: case ZEND_PRE_INC:
@ -481,7 +468,9 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_bool reor
/* Mark instruction with side effects as live */ /* Mark instruction with side effects as live */
FOREACH_INSTR_NUM(i) { FOREACH_INSTR_NUM(i) {
if (may_have_side_effects(&ctx, &op_array->opcodes[i], &ssa->ops[i]) || has_varargs) { if (may_have_side_effects(op_array, ssa, &op_array->opcodes[i], &ssa->ops[i], ctx.reorder_dtor_effects)
|| zend_may_throw(&op_array->opcodes[i], op_array, ssa)
|| has_varargs) {
zend_bitset_excl(ctx.instr_dead, i); zend_bitset_excl(ctx.instr_dead, i);
add_operands_to_worklists(&ctx, &op_array->opcodes[i], &ssa->ops[i]); add_operands_to_worklists(&ctx, &op_array->opcodes[i], &ssa->ops[i]);
} }

View file

@ -4024,6 +4024,7 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa
case ZEND_COALESCE: case ZEND_COALESCE:
case ZEND_SWITCH_LONG: case ZEND_SWITCH_LONG:
case ZEND_SWITCH_STRING: case ZEND_SWITCH_STRING:
case ZEND_ISSET_ISEMPTY_VAR:
return 0; return 0;
case ZEND_INIT_FCALL: case ZEND_INIT_FCALL:
/* can't throw, because call is resolved at compile time */ /* can't throw, because call is resolved at compile time */
@ -4157,6 +4158,7 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa
return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) || return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) ||
(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)); (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT));
case ZEND_ASSIGN: case ZEND_ASSIGN:
case ZEND_UNSET_VAR:
return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)); return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY));
case ZEND_ASSIGN_DIM: case ZEND_ASSIGN_DIM:
return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_LONG|MAY_BE_DOUBLE)) || opline->op2_type == IS_UNUSED || return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_LONG|MAY_BE_DOUBLE)) || opline->op2_type == IS_UNUSED ||