Use guards for ZEND_FETCH_OBJ_R/IS to eliminate repeatable checks

This commit is contained in:
Dmitry Stogov 2020-06-18 11:10:47 +03:00
parent e42cab2088
commit 8cbb0ffcb1
3 changed files with 46 additions and 15 deletions

View file

@ -2767,9 +2767,14 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
ce = NULL; ce = NULL;
if (opline->op1_type == IS_UNUSED) { if (opline->op1_type == IS_UNUSED) {
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN; op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
op1_addr = 0;
ce = op_array->scope; ce = op_array->scope;
} else { } else {
op1_info = OP1_INFO(); op1_info = OP1_INFO();
if (!(op1_info & MAY_BE_OBJECT)) {
break;
}
op1_addr = OP1_REG_ADDR();
if (ssa->var_info && ssa->ops) { if (ssa->var_info && ssa->ops) {
zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes]; zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
if (ssa_op->op1_use >= 0) { if (ssa_op->op1_use >= 0) {
@ -2780,11 +2785,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
} }
} }
} }
if (!(op1_info & MAY_BE_OBJECT)) {
break;
}
if (!zend_jit_fetch_obj_read(&dasm_state, opline, op_array, if (!zend_jit_fetch_obj_read(&dasm_state, opline, op_array,
op1_info, ce, op1_info, op1_addr, ce,
zend_may_throw(opline, ssa_op, op_array, ssa))) { zend_may_throw(opline, ssa_op, op_array, ssa))) {
goto jit_failure; goto jit_failure;
} }

View file

@ -1547,6 +1547,23 @@ propagate_arg:
} }
} }
break; break;
case ZEND_FETCH_OBJ_FUNC_ARG:
if (!frame
|| !frame->call
|| !frame->call->func
|| !TRACE_FRAME_IS_LAST_SEND_BY_VAL(frame->call)) {
break;
}
/* break missing intentionally */
case ZEND_FETCH_OBJ_R:
case ZEND_FETCH_OBJ_IS:
if (opline->op2_type != IS_CONST
|| Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
break;
}
ADD_OP1_TRACE_GUARD();
break;
default: default:
break; break;
} }
@ -3720,8 +3737,21 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
if (opline->op1_type == IS_UNUSED) { if (opline->op1_type == IS_UNUSED) {
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN; op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
ce = op_array->scope; ce = op_array->scope;
op1_addr = 0;
} else { } else {
op1_info = OP1_INFO(); op1_info = OP1_INFO();
if (!(op1_info & MAY_BE_OBJECT)) {
break;
}
op1_addr = OP1_REG_ADDR();
if (orig_op1_type != IS_UNKNOWN
&& (orig_op1_type & IS_TRACE_REFERENCE)) {
if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr, 1)) {
goto jit_failure;
}
} else {
CHECK_OP1_TRACE_TYPE();
}
if (ssa->var_info && ssa->ops) { if (ssa->var_info && ssa->ops) {
if (ssa_op->op1_use >= 0) { if (ssa_op->op1_use >= 0) {
zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use; zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
@ -3731,11 +3761,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
} }
} }
} }
if (!(op1_info & MAY_BE_OBJECT)) {
break;
}
if (!zend_jit_fetch_obj_read(&dasm_state, opline, op_array, if (!zend_jit_fetch_obj_read(&dasm_state, opline, op_array,
op1_info, ce, op1_info, op1_addr, ce,
zend_may_throw(opline, ssa_op, op_array, ssa))) { zend_may_throw(opline, ssa_op, op_array, ssa))) {
goto jit_failure; goto jit_failure;
} }

View file

@ -10789,12 +10789,11 @@ static zend_bool zend_may_be_dynamic_property(zend_class_entry *ce, zend_string
return 0; return 0;
} }
static int zend_jit_fetch_obj_read(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_class_entry *ce, int may_throw) static int zend_jit_fetch_obj_read(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, zend_class_entry *ce, int may_throw)
{ {
zval *member; zval *member;
uint32_t offset; uint32_t offset;
zend_bool may_be_dynamic = 1; zend_bool may_be_dynamic = 1;
zend_jit_addr op1_addr = 0, orig_op1_addr = 0;
zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This)); zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
zend_jit_addr prop_addr; zend_jit_addr prop_addr;
@ -10809,11 +10808,10 @@ static int zend_jit_fetch_obj_read(dasm_State **Dst, const zend_op *opline, cons
if (opline->op1_type == IS_UNUSED) { if (opline->op1_type == IS_UNUSED) {
| GET_ZVAL_PTR FCARG1a, this_addr | GET_ZVAL_PTR FCARG1a, this_addr
} else { } else {
op1_addr = orig_op1_addr = OP1_ADDR();
if (op1_info & MAY_BE_REF) { if (op1_info & MAY_BE_REF) {
| LOAD_ZVAL_ADDR r0, op1_addr | LOAD_ZVAL_ADDR FCARG1a, op1_addr
| ZVAL_DEREF r0, op1_info | ZVAL_DEREF FCARG1a, op1_info
op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0); op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
} }
if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) { if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
@ -10895,14 +10893,18 @@ static int zend_jit_fetch_obj_read(dasm_State **Dst, const zend_op *opline, cons
if (opline->opcode != ZEND_FETCH_OBJ_IS) { if (opline->opcode != ZEND_FETCH_OBJ_IS) {
| SAVE_VALID_OPLINE opline, r1 | SAVE_VALID_OPLINE opline, r1
if (op1_info & MAY_BE_UNDEF) { if (op1_info & MAY_BE_UNDEF) {
zend_jit_addr orig_op1_addr = OP1_ADDR();
if (op1_info & MAY_BE_ANY) { if (op1_info & MAY_BE_ANY) {
| IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1 | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1
} }
| mov FCARG1d, opline->op1.var | mov FCARG1d, opline->op1.var
| EXT_CALL zend_jit_undefined_op_helper, r0 | EXT_CALL zend_jit_undefined_op_helper, r0
|1: |1:
}
| LOAD_ZVAL_ADDR FCARG1a, orig_op1_addr | LOAD_ZVAL_ADDR FCARG1a, orig_op1_addr
} else {
| LOAD_ZVAL_ADDR FCARG1a, op1_addr
}
| LOAD_ADDR FCARG2a, Z_STRVAL_P(member) | LOAD_ADDR FCARG2a, Z_STRVAL_P(member)
| EXT_CALL zend_jit_invalid_property_read, r0 | EXT_CALL zend_jit_invalid_property_read, r0
} }