mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
JIT: Add CPU registers support for FETCH_OBJ_R (#14253)
This commit is contained in:
@@ -2338,7 +2338,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
|
||||
}
|
||||
if (!zend_jit_fetch_obj(&ctx, opline, op_array, ssa, ssa_op,
|
||||
op1_info, op1_addr, 0, ce, ce_is_instanceof, on_this, 0, 0, NULL,
|
||||
IS_UNKNOWN,
|
||||
RES_REG_ADDR(), IS_UNKNOWN,
|
||||
zend_may_throw(opline, ssa_op, op_array, ssa))) {
|
||||
goto jit_failure;
|
||||
}
|
||||
|
||||
@@ -1956,6 +1956,110 @@ static void ZEND_FASTCALL zend_jit_fetch_obj_is_dynamic(zend_object *zobj, intpt
|
||||
zend_jit_fetch_obj_is_slow(zobj);
|
||||
}
|
||||
|
||||
static zval* ZEND_FASTCALL zend_jit_fetch_obj_r_slow_ex(zend_object *zobj)
|
||||
{
|
||||
zval *retval;
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
const zend_op *opline = EX(opline);
|
||||
zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
|
||||
|
||||
retval = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, result);
|
||||
if (retval == result && UNEXPECTED(Z_ISREF_P(retval))) {
|
||||
zend_unwrap_reference(retval);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static zval* ZEND_FASTCALL zend_jit_fetch_obj_r_dynamic_ex(zend_object *zobj, intptr_t prop_offset)
|
||||
{
|
||||
if (zobj->properties) {
|
||||
zval *retval;
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
const zend_op *opline = EX(opline);
|
||||
zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
|
||||
void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
|
||||
|
||||
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
|
||||
intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
|
||||
|
||||
if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
|
||||
Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
|
||||
|
||||
if (EXPECTED(p->key == name) ||
|
||||
(EXPECTED(p->h == ZSTR_H(name)) &&
|
||||
EXPECTED(p->key != NULL) &&
|
||||
EXPECTED(zend_string_equal_content(p->key, name)))) {
|
||||
return &p->val;
|
||||
}
|
||||
}
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
|
||||
}
|
||||
|
||||
retval = zend_hash_find_known_hash(zobj->properties, name);
|
||||
|
||||
if (EXPECTED(retval)) {
|
||||
intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
return zend_jit_fetch_obj_r_slow_ex(zobj);
|
||||
}
|
||||
|
||||
static zval* ZEND_FASTCALL zend_jit_fetch_obj_is_slow_ex(zend_object *zobj)
|
||||
{
|
||||
zval *retval;
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
const zend_op *opline = EX(opline);
|
||||
zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
|
||||
|
||||
retval = zobj->handlers->read_property(zobj, name, BP_VAR_IS, cache_slot, result);
|
||||
if (retval == result && UNEXPECTED(Z_ISREF_P(retval))) {
|
||||
zend_unwrap_reference(retval);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static zval* ZEND_FASTCALL zend_jit_fetch_obj_is_dynamic_ex(zend_object *zobj, intptr_t prop_offset)
|
||||
{
|
||||
if (zobj->properties) {
|
||||
zval *retval;
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
const zend_op *opline = EX(opline);
|
||||
zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
|
||||
void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
|
||||
|
||||
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
|
||||
intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
|
||||
|
||||
if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
|
||||
Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
|
||||
|
||||
if (EXPECTED(p->key == name) ||
|
||||
(EXPECTED(p->h == ZSTR_H(name)) &&
|
||||
EXPECTED(p->key != NULL) &&
|
||||
EXPECTED(zend_string_equal_content(p->key, name)))) {
|
||||
return &p->val;
|
||||
}
|
||||
}
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
|
||||
}
|
||||
|
||||
retval = zend_hash_find_known_hash(zobj->properties, name);
|
||||
|
||||
if (EXPECTED(retval)) {
|
||||
intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
|
||||
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
return zend_jit_fetch_obj_is_slow_ex(zobj);
|
||||
}
|
||||
|
||||
static zend_always_inline bool promotes_to_array(zval *val) {
|
||||
return Z_TYPE_P(val) <= IS_FALSE
|
||||
|| (Z_ISREF_P(val) && Z_TYPE_P(Z_REFVAL_P(val)) <= IS_FALSE);
|
||||
|
||||
@@ -3039,9 +3039,13 @@ static void zend_jit_setup_disasm(void)
|
||||
REGISTER_HELPER(zend_jit_assign_dim_op_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_r_slow_ex);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_is_slow_ex);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic_ex);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic_ex);
|
||||
REGISTER_HELPER(zend_jit_check_array_promotion);
|
||||
REGISTER_HELPER(zend_jit_create_typed_ref);
|
||||
REGISTER_HELPER(zend_jit_invalid_property_write);
|
||||
@@ -13662,13 +13666,13 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit,
|
||||
bool delayed_fetch_this,
|
||||
bool op1_avoid_refcounting,
|
||||
zend_class_entry *trace_ce,
|
||||
zend_jit_addr res_addr,
|
||||
uint8_t prop_type,
|
||||
int may_throw)
|
||||
{
|
||||
zval *member;
|
||||
zend_property_info *prop_info;
|
||||
bool may_be_dynamic = 1;
|
||||
zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
|
||||
zend_jit_addr prop_addr;
|
||||
uint32_t res_info = RES_INFO();
|
||||
ir_ref prop_type_ref = IR_UNUSED;
|
||||
@@ -13676,6 +13680,7 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit,
|
||||
ir_ref prop_ref = IR_UNUSED;
|
||||
ir_ref end_inputs = IR_UNUSED;
|
||||
ir_ref slow_inputs = IR_UNUSED;
|
||||
ir_ref end_values = IR_UNUSED;
|
||||
|
||||
ZEND_ASSERT(opline->op2_type == IS_CONST);
|
||||
ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
|
||||
@@ -13804,13 +13809,28 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit,
|
||||
jit_SET_EX_OPLINE(jit, opline);
|
||||
|
||||
if (opline->opcode != ZEND_FETCH_OBJ_IS) {
|
||||
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic),
|
||||
obj_ref, offset_ref);
|
||||
if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
|
||||
|| Z_MODE(res_addr) == IS_REG) {
|
||||
ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic_ex),
|
||||
obj_ref, offset_ref);
|
||||
ir_END_PHI_list(end_values, val_addr);
|
||||
} else {
|
||||
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic),
|
||||
obj_ref, offset_ref);
|
||||
ir_END_list(end_inputs);
|
||||
}
|
||||
} else {
|
||||
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic),
|
||||
obj_ref, offset_ref);
|
||||
if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
|
||||
|| Z_MODE(res_addr) == IS_REG) {
|
||||
ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic_ex),
|
||||
obj_ref, offset_ref);
|
||||
ir_END_PHI_list(end_values, val_addr);
|
||||
} else {
|
||||
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic),
|
||||
obj_ref, offset_ref);
|
||||
ir_END_list(end_inputs);
|
||||
}
|
||||
}
|
||||
ir_END_list(end_inputs);
|
||||
}
|
||||
ir_IF_FALSE(if_dynamic);
|
||||
}
|
||||
@@ -13996,12 +14016,56 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit,
|
||||
}
|
||||
ir_END_list(end_inputs);
|
||||
} else {
|
||||
if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
|
||||
|| Z_MODE(res_addr) == IS_REG) {
|
||||
ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
|
||||
} else {
|
||||
prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
|
||||
|
||||
if (!zend_jit_zval_copy_deref(jit, res_addr, prop_addr, prop_type_ref)) {
|
||||
return 0;
|
||||
}
|
||||
ir_END_list(end_inputs);
|
||||
}
|
||||
}
|
||||
|
||||
if (op1_avoid_refcounting) {
|
||||
SET_STACK_REG(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
|
||||
}
|
||||
|
||||
if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
|
||||
ir_MERGE_list(slow_inputs);
|
||||
jit_SET_EX_OPLINE(jit, opline);
|
||||
|
||||
if (opline->opcode == ZEND_FETCH_OBJ_W) {
|
||||
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_w_slow), obj_ref);
|
||||
ir_END_list(end_inputs);
|
||||
} else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
|
||||
if (Z_MODE(res_addr) == IS_REG) {
|
||||
ir_ref val_ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow_ex), obj_ref);
|
||||
ir_END_PHI_list(end_values, val_ref);
|
||||
} else {
|
||||
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow), obj_ref);
|
||||
ir_END_list(end_inputs);
|
||||
}
|
||||
} else {
|
||||
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_slow), obj_ref);
|
||||
ir_END_list(end_inputs);
|
||||
}
|
||||
}
|
||||
|
||||
if (end_values) {
|
||||
ir_ref val_ref = ir_PHI_list(end_values);
|
||||
zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val_ref);
|
||||
bool result_avoid_refcounting = 0;
|
||||
|
||||
if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) {
|
||||
ZEND_ASSERT(opline->opcode == ZEND_FETCH_OBJ_R
|
||||
|| opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG
|
||||
|| opline->opcode == ZEND_FETCH_OBJ_IS);
|
||||
ZEND_ASSERT(end_inputs == IR_UNUSED);
|
||||
if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
|
||||
uint8_t type = concrete_type(res_info);
|
||||
uint32_t flags = 0;
|
||||
zend_jit_addr val_addr = prop_addr;
|
||||
|
||||
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
|
||||
&& !delayed_fetch_this
|
||||
@@ -14026,39 +14090,14 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit,
|
||||
|
||||
res_info &= ~MAY_BE_GUARD;
|
||||
ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
|
||||
|
||||
// ZVAL_COPY
|
||||
jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
|
||||
} else {
|
||||
prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
|
||||
|
||||
if (!zend_jit_zval_copy_deref(jit, res_addr, prop_addr, prop_type_ref)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ir_END_list(end_inputs);
|
||||
|
||||
// ZVAL_COPY
|
||||
jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
|
||||
} else {
|
||||
ir_MERGE_list(end_inputs);
|
||||
}
|
||||
|
||||
if (op1_avoid_refcounting) {
|
||||
SET_STACK_REG(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
|
||||
}
|
||||
|
||||
if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
|
||||
ir_MERGE_list(slow_inputs);
|
||||
jit_SET_EX_OPLINE(jit, opline);
|
||||
|
||||
if (opline->opcode == ZEND_FETCH_OBJ_W) {
|
||||
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_w_slow), obj_ref);
|
||||
} else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
|
||||
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow), obj_ref);
|
||||
} else {
|
||||
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_slow), obj_ref);
|
||||
}
|
||||
ir_END_list(end_inputs);
|
||||
}
|
||||
|
||||
ir_MERGE_list(end_inputs);
|
||||
|
||||
if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
|
||||
if (opline->op1_type == IS_VAR
|
||||
&& opline->opcode == ZEND_FETCH_OBJ_W
|
||||
@@ -16662,6 +16701,14 @@ static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa
|
||||
return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
|
||||
(((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
|
||||
((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
|
||||
case ZEND_FETCH_OBJ_R:
|
||||
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') {
|
||||
return 0;
|
||||
}
|
||||
op1_info = OP1_INFO();
|
||||
return opline->op1_type == IS_UNUSED || (op1_info & MAY_BE_OBJECT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2963,6 +2963,7 @@ static zend_jit_reg_var* zend_jit_trace_allocate_registers(zend_jit_trace_rec *t
|
||||
|| opline->opcode == ZEND_SUB
|
||||
|| opline->opcode == ZEND_MUL
|
||||
|| opline->opcode == ZEND_FETCH_DIM_R
|
||||
|| opline->opcode == ZEND_FETCH_OBJ_R
|
||||
|| opline->opcode == ZEND_FETCH_CONSTANT) {
|
||||
if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_DOUBLE)
|
||||
|| (opline->opcode != ZEND_PRE_INC && opline->opcode != ZEND_PRE_DEC)) {
|
||||
@@ -6004,7 +6005,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
}
|
||||
if (!zend_jit_fetch_obj(&ctx, opline, op_array, ssa, ssa_op,
|
||||
op1_info, op1_addr, op1_indirect, ce, ce_is_instanceof,
|
||||
on_this, delayed_fetch_this, avoid_refcounting, op1_ce, val_type,
|
||||
on_this, delayed_fetch_this, avoid_refcounting, op1_ce,
|
||||
RES_REG_ADDR(), val_type,
|
||||
zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, MAY_BE_STRING))) {
|
||||
goto jit_failure;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user