1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 08:12:21 +01:00

JIT: Add CPU registers support for ASSIGN_OBJ and ASSIGN_OBJ_OP (#14303)

* JIT: Add CPU registers support for ASSIGN_OBJ and ASSIGN_OBJ_OP

* Fix tests failures

* Fix tests failures

* Add missing GUARD
This commit is contained in:
Dmitry Stogov
2024-05-23 19:25:06 +03:00
committed by GitHub
parent 706e9ed058
commit 58c281a6cf
3 changed files with 152 additions and 26 deletions

View File

@@ -1817,7 +1817,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
}
}
if (!zend_jit_assign_obj_op(&ctx, opline, op_array, ssa, ssa_op,
op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_RANGE(),
op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_REG_ADDR(), OP1_DATA_RANGE(),
0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN)) {
goto jit_failure;
}
@@ -1861,7 +1861,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
}
}
if (!zend_jit_assign_obj(&ctx, opline, op_array, ssa, ssa_op,
op1_info, op1_addr, OP1_DATA_INFO(),
op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_REG_ADDR(), OP1_DATA_DEF_REG_ADDR(),
(opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN,
zend_may_throw(opline, ssa_op, op_array, ssa))) {
goto jit_failure;

View File

@@ -6254,7 +6254,7 @@ static int zend_jit_assign_to_variable(zend_jit_ctx *jit,
if (Z_MODE(val_addr) == IS_REG) {
zend_jit_addr real_addr;
if (opline->opcode == ZEND_ASSIGN_DIM) {
if (opline->opcode == ZEND_ASSIGN_DIM || opline->opcode == ZEND_ASSIGN_OBJ) {
real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
} else {
ZEND_ASSERT(opline->opcode == ZEND_ASSIGN);
@@ -14143,6 +14143,9 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
uint32_t op1_info,
zend_jit_addr op1_addr,
uint32_t val_info,
zend_jit_addr val_addr,
zend_jit_addr val_def_addr,
zend_jit_addr res_addr,
bool op1_indirect,
zend_class_entry *ce,
bool ce_is_instanceof,
@@ -14155,17 +14158,21 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
zval *member;
zend_string *name;
zend_property_info *prop_info;
zend_jit_addr val_addr = OP1_DATA_ADDR();
zend_jit_addr res_addr = 0;
zend_jit_addr prop_addr;
ir_ref obj_ref = IR_UNUSED;
ir_ref prop_ref = IR_UNUSED;
ir_ref delayed_end_input = IR_UNUSED;
ir_ref end_inputs = IR_UNUSED;
ir_ref slow_inputs = IR_UNUSED;
uint32_t res_info = RES_INFO();
if (RETURN_VALUE_USED(opline)) {
res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
if (val_addr != val_def_addr && val_def_addr) {
if (!zend_jit_update_regs(jit, (opline+1)->op1.var, val_addr, val_def_addr, val_info)) {
return 0;
}
if (Z_MODE(val_def_addr) == IS_REG && Z_MODE(val_addr) != IS_REG) {
val_addr = val_def_addr;
}
}
ZEND_ASSERT(opline->op2_type == IS_CONST);
@@ -14206,7 +14213,7 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
jit_ZVAL_ADDR(jit, op1_addr),
ir_CONST_ADDR(ZSTR_VAL(name)));
if (RETURN_VALUE_USED(opline)) {
if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) != IS_REG) {
jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
}
@@ -14276,18 +14283,37 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
ir_ref arg3, arg4;
ir_ref prop_info_ref = ir_LOAD_A(
ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
ir_ref if_has_prop_info = ir_IF(prop_info_ref);
ir_IF_TRUE_cold(if_has_prop_info);
if (Z_MODE(val_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
return 0;
}
arg3 = jit_ZVAL_ADDR(jit, real_addr);
} else {
arg3 = jit_ZVAL_ADDR(jit, val_addr);
}
if (!RETURN_VALUE_USED(opline)) {
arg4 = IR_NULL;
} else if (Z_MODE(res_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
arg4 = jit_ZVAL_ADDR(jit, real_addr);
} else {
arg4 = jit_ZVAL_ADDR(jit, res_addr);
}
// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
jit_SET_EX_OPLINE(jit, opline);
ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
prop_ref,
prop_info_ref,
jit_ZVAL_ADDR(jit, val_addr),
RETURN_VALUE_USED(opline) ? jit_ZVAL_ADDR(jit, res_addr) : IR_NULL);
arg3,
arg4);
if ((opline+1)->op1_type == IS_CONST) {
// TODO: ???
@@ -14295,6 +14321,13 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
// CACHE_PTR_EX(cache_slot + 2, NULL);
}
if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
return 0;
}
}
ir_END_list(end_inputs);
ir_IF_FALSE(if_has_prop_info);
}
@@ -14319,7 +14352,7 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
}
}
if (ZEND_TYPE_IS_SET(prop_info->type)) {
ir_ref ref;
ir_ref ref, arg3, arg4;
// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
jit_SET_EX_OPLINE(jit, opline);
@@ -14333,18 +14366,43 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
}
if (Z_MODE(val_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
return 0;
}
arg3 = jit_ZVAL_ADDR(jit, real_addr);
} else {
arg3 = jit_ZVAL_ADDR(jit, val_addr);
}
if (!RETURN_VALUE_USED(opline)) {
arg4 = IR_NULL;
} else if (Z_MODE(res_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
arg4 = jit_ZVAL_ADDR(jit, real_addr);
} else {
arg4 = jit_ZVAL_ADDR(jit, res_addr);
}
ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
prop_ref,
ref,
jit_ZVAL_ADDR(jit, val_addr),
RETURN_VALUE_USED(opline) ? jit_ZVAL_ADDR(jit, res_addr) : IR_NULL);
arg3,
arg4);
if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
return 0;
}
}
ir_END_list(end_inputs);
}
}
if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
if (opline->result_type == IS_UNUSED) {
if (Z_MODE(val_addr) != IS_REG
&& (res_addr == 0 || Z_MODE(res_addr) != IS_REG)
&& opline->result_type == IS_UNUSED) {
if (!zend_jit_assign_to_variable_call(jit, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) {
return 0;
}
@@ -14365,18 +14423,44 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
}
if (slow_inputs) {
ir_ref arg3, arg5;
ir_MERGE_list(slow_inputs);
jit_SET_EX_OPLINE(jit, opline);
if (Z_MODE(val_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
return 0;
}
arg3 = jit_ZVAL_ADDR(jit, real_addr);
} else {
arg3 = jit_ZVAL_ADDR(jit, val_addr);
}
if (!RETURN_VALUE_USED(opline)) {
arg5 = IR_NULL;
} else if (Z_MODE(res_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
arg5 = jit_ZVAL_ADDR(jit, real_addr);
} else {
arg5 = jit_ZVAL_ADDR(jit, res_addr);
}
// JIT: value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_helper),
obj_ref,
ir_CONST_ADDR(name),
jit_ZVAL_ADDR(jit, val_addr),
arg3,
ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
RETURN_VALUE_USED(opline) ? jit_ZVAL_ADDR(jit, res_addr) : IR_NULL);
arg5);
if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
return 0;
}
}
ir_END_list(end_inputs);
}
@@ -14412,6 +14496,7 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
uint32_t op1_info,
zend_jit_addr op1_addr,
uint32_t val_info,
zend_jit_addr val_addr,
zend_ssa_range *val_range,
bool op1_indirect,
zend_class_entry *ce,
@@ -14424,7 +14509,6 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
zval *member;
zend_string *name;
zend_property_info *prop_info;
zend_jit_addr val_addr = OP1_DATA_ADDR();
zend_jit_addr prop_addr;
bool use_prop_guard = 0;
bool may_throw = 0;
@@ -14579,12 +14663,22 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
}
}
if (ZEND_TYPE_IS_SET(prop_info->type)) {
ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref;
ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
may_throw = 1;
jit_SET_EX_OPLINE(jit, opline);
if (Z_MODE(val_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
return 0;
}
arg2 = jit_ZVAL_ADDR(jit, real_addr);
} else {
arg2 = jit_ZVAL_ADDR(jit, val_addr);
}
if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
ir_IF_FALSE(if_ref);
noref_path = ir_END();
@@ -14599,7 +14693,7 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
reference,
jit_ZVAL_ADDR(jit, val_addr),
arg2,
ir_CONST_FC_FUNC(binary_op));
ir_END_list(end_inputs);
@@ -14623,7 +14717,7 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_prop),
prop_ref,
ref,
jit_ZVAL_ADDR(jit, val_addr),
arg2,
ir_CONST_FC_FUNC(binary_op));
ir_END_list(end_inputs);
@@ -14647,7 +14741,7 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
}
if (var_info & MAY_BE_REF) {
ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref;
ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
may_throw = 1;
@@ -14665,9 +14759,18 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
jit_SET_EX_OPLINE(jit, opline);
if (Z_MODE(val_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
return 0;
}
arg2 = jit_ZVAL_ADDR(jit, real_addr);
} else {
arg2 = jit_ZVAL_ADDR(jit, val_addr);
}
ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
reference,
jit_ZVAL_ADDR(jit, val_addr),
arg2,
ir_CONST_FC_FUNC(binary_op));
ir_END_list(end_inputs);
@@ -14760,16 +14863,27 @@ long_math:
}
if (slow_inputs) {
ir_ref arg3;
ir_MERGE_list(slow_inputs);
may_throw = 1;
if (Z_MODE(val_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
return 0;
}
arg3 = jit_ZVAL_ADDR(jit, real_addr);
} else {
arg3 = jit_ZVAL_ADDR(jit, val_addr);
}
jit_SET_EX_OPLINE(jit, opline);
ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_op_helper),
obj_ref,
ir_CONST_ADDR(name),
jit_ZVAL_ADDR(jit, val_addr),
arg3,
ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
ir_CONST_FC_FUNC(binary_op));
@@ -16692,7 +16806,16 @@ 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_ASSIGN_OBJ_OP:
if (opline->result_type != IS_UNUSED) {
return 0;
}
if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
return 0;
}
ZEND_FALLTHROUGH;
case ZEND_FETCH_OBJ_R:
case ZEND_ASSIGN_OBJ:
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') {

View File

@@ -1843,7 +1843,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
break;
}
if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
if (opline->opcode == ZEND_ASSIGN_OBJ
|| opline->opcode == ZEND_ASSIGN_OBJ_OP) {
if (opline->op1_type == IS_CV
&& (opline+1)->op1_type == IS_CV
&& (opline+1)->op1.var == opline->op1.var) {
@@ -4851,7 +4852,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op1_data_info = OP1_DATA_INFO();
CHECK_OP1_DATA_TRACE_TYPE();
if (!zend_jit_assign_obj_op(&ctx, opline, op_array, ssa, ssa_op,
op1_info, op1_addr, op1_data_info, OP1_DATA_RANGE(),
op1_info, op1_addr, op1_data_info, OP1_DATA_REG_ADDR(), OP1_DATA_RANGE(),
op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
val_type)) {
goto jit_failure;
@@ -4934,7 +4935,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op1_data_info = OP1_DATA_INFO();
CHECK_OP1_DATA_TRACE_TYPE();
if (!zend_jit_assign_obj(&ctx, opline, op_array, ssa, ssa_op,
op1_info, op1_addr, op1_data_info,
op1_info, op1_addr, op1_data_info, OP1_DATA_REG_ADDR(), OP1_DATA_DEF_REG_ADDR(),
(opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
val_type,
zend_may_throw(opline, ssa_op, op_array, ssa))) {