From: Dmitry Stogov Date: Wed, 8 Jul 2020 11:09:28 +0000 (+0300) Subject: Use information about recorded classes for speculative FETCH_OBJ optimization X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9e8a8e6ab9c30046c72baca6b65c6282e59586c1;p=php Use information about recorded classes for speculative FETCH_OBJ optimization --- diff --git a/ext/opcache/Optimizer/zend_inference.h b/ext/opcache/Optimizer/zend_inference.h index 98a647f43a..0708d5df94 100644 --- a/ext/opcache/Optimizer/zend_inference.h +++ b/ext/opcache/Optimizer/zend_inference.h @@ -26,6 +26,7 @@ /* Bitmask for type inference (zend_ssa_var_info.type) */ #include "zend_type_info.h" +#define MAY_BE_CLASS_GUARD (1<<27) /* needs class guard */ #define MAY_BE_GUARD (1<<28) /* needs type guard */ #define MAY_BE_IN_REG (1<<29) /* value allocated in CPU register */ diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 3b7c9e1ec4..debf4df866 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2790,8 +2790,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } } } - if (!zend_jit_fetch_obj(&dasm_state, opline, op_array, - op1_info, op1_addr, 0, ce, ce_is_instanceof, 0, + if (!zend_jit_fetch_obj(&dasm_state, opline, op_array, ssa, ssa_op, + op1_info, op1_addr, 0, ce, ce_is_instanceof, 0, NULL, 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 e207aa35d1..ca8c72ff3f 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -2921,6 +2921,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par uint8_t op3_type = p->op3_type; uint8_t orig_op1_type = op1_type; zend_bool op1_indirect; + zend_class_entry *op1_ce = NULL; opline = p->opline; if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) { @@ -2934,7 +2935,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par } if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) { - // TODO: support for recorded classes ??? + op1_ce = (zend_class_entry*)(p+1)->ce; p++; } if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) { @@ -3837,9 +3838,9 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this; } } - if (!zend_jit_fetch_obj(&dasm_state, opline, op_array, + if (!zend_jit_fetch_obj(&dasm_state, opline, op_array, ssa, ssa_op, op1_info, op1_addr, op1_indirect, ce, ce_is_instanceof, - delayed_fetch_this, + delayed_fetch_this, op1_ce, zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, MAY_BE_STRING))) { goto jit_failure; } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 04573476d2..12dccc00ff 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -10898,7 +10898,31 @@ static zend_bool zend_may_be_dynamic_property(zend_class_entry *ce, zend_string return 0; } -static int zend_jit_fetch_obj(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, zend_bool op1_indirect, zend_class_entry *ce, zend_bool ce_is_instanceof, zend_bool use_this, int may_throw) +static int zend_jit_class_guard(dasm_State **Dst, const zend_op *opline, zend_class_entry *ce) +{ + int32_t exit_point = zend_jit_trace_get_exit_point(opline, opline, NULL, 0); + const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); + + if (!exit_addr) { + return 0; + } + + |.if X64 + || if (!IS_SIGNED_32BIT(ce)) { + | mov64 r0, ((ptrdiff_t)ce) + | cmp aword [FCARG1a + offsetof(zend_object, ce)], r0 + || } else { + | cmp aword [FCARG1a + offsetof(zend_object, ce)], ce + || } + |.else + | cmp aword [FCARG1a + offsetof(zend_object, ce)], ce + |.endif + | jne &exit_addr + + return 1; +} + +static int zend_jit_fetch_obj(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, uint32_t op1_info, zend_jit_addr op1_addr, zend_bool op1_indirect, zend_class_entry *ce, zend_bool ce_is_instanceof, zend_bool use_this, zend_class_entry *trace_ce, int may_throw) { zval *member; zend_property_info *prop_info; @@ -10950,6 +10974,20 @@ static int zend_jit_fetch_obj(dasm_State **Dst, const zend_op *opline, const zen | GET_ZVAL_PTR FCARG1a, op1_addr } + if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) { + prop_info = zend_get_known_property_info(trace_ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename); + if (prop_info) { + if (!(op1_info & MAY_BE_CLASS_GUARD)) { + if (!zend_jit_class_guard(Dst, opline, trace_ce)) { + return 0; + } + if (ssa->var_info && ssa_op->op1_use >= 0) { + ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD; + } + } + } + } + if (!prop_info) { | mov r0, EX->run_time_cache | mov r2, aword [r0 + (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS)]