From: Dmitry Stogov Date: Thu, 18 Jun 2020 08:10:47 +0000 (+0300) Subject: Use guards for ZEND_FETCH_OBJ_R/IS to eliminate repeatable checks X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8cbb0ffcb1b6eb8382e0c90b4eae59ce85b3fdd1;p=php Use guards for ZEND_FETCH_OBJ_R/IS to eliminate repeatable checks --- diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 3f37a07b3e..223dd53ba6 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2767,9 +2767,14 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op ce = NULL; if (opline->op1_type == IS_UNUSED) { op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN; + op1_addr = 0; ce = op_array->scope; } else { op1_info = OP1_INFO(); + if (!(op1_info & MAY_BE_OBJECT)) { + break; + } + op1_addr = OP1_REG_ADDR(); if (ssa->var_info && ssa->ops) { zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes]; 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, - op1_info, ce, + op1_info, op1_addr, ce, zend_may_throw(opline, ssa_op, op_array, ssa))) { goto jit_failure; } diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 33e0cd714c..3bcb5a7697 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -1547,6 +1547,23 @@ propagate_arg: } } 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: 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) { op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN; ce = op_array->scope; + op1_addr = 0; } else { 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_op->op1_use >= 0) { 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, - op1_info, ce, + op1_info, op1_addr, ce, zend_may_throw(opline, ssa_op, op_array, ssa))) { goto jit_failure; } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index d0be13b108..576bb7badb 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -10789,12 +10789,11 @@ static zend_bool zend_may_be_dynamic_property(zend_class_entry *ce, zend_string 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; uint32_t offset; 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 this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This)); 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) { | GET_ZVAL_PTR FCARG1a, this_addr } else { - op1_addr = orig_op1_addr = OP1_ADDR(); if (op1_info & MAY_BE_REF) { - | LOAD_ZVAL_ADDR r0, op1_addr - | ZVAL_DEREF r0, op1_info - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0); + | LOAD_ZVAL_ADDR FCARG1a, op1_addr + | ZVAL_DEREF FCARG1a, op1_info + op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0); } if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) { 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) { | SAVE_VALID_OPLINE opline, r1 if (op1_info & MAY_BE_UNDEF) { + zend_jit_addr orig_op1_addr = OP1_ADDR(); + if (op1_info & MAY_BE_ANY) { | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1 } | mov FCARG1d, opline->op1.var | EXT_CALL zend_jit_undefined_op_helper, r0 |1: + | LOAD_ZVAL_ADDR FCARG1a, orig_op1_addr + } else { + | LOAD_ZVAL_ADDR FCARG1a, op1_addr } - | LOAD_ZVAL_ADDR FCARG1a, orig_op1_addr | LOAD_ADDR FCARG2a, Z_STRVAL_P(member) | EXT_CALL zend_jit_invalid_property_read, r0 }