From 230547a7b9183453d33b7f95b87c0d075bf56408 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 23 May 2024 15:00:07 +0300 Subject: [PATCH 1/4] JIT: Add CPU registers support for ASSIGN_OBJ and ASSIGN_OBJ_OP --- ext/opcache/jit/zend_jit.c | 4 +-- ext/opcache/jit/zend_jit_ir.c | 54 ++++++++++++++++++++++++++++---- ext/opcache/jit/zend_jit_trace.c | 4 +-- 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index fe4043eac00e5..6c226cd6c9b01 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -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,7 @@ 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(), 0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN, zend_may_throw(opline, ssa_op, op_array, ssa))) { goto jit_failure; diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index edd7f9a2f2490..59533c60db58d 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -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,8 @@ 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, bool op1_indirect, zend_class_entry *ce, bool ce_is_instanceof, @@ -14155,7 +14157,6 @@ 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; @@ -14164,6 +14165,15 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, ir_ref end_inputs = IR_UNUSED; ir_ref slow_inputs = IR_UNUSED; + 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; + } + } + if (RETURN_VALUE_USED(opline)) { res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); } @@ -14276,17 +14286,28 @@ 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; 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); + } + // 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), + arg3, RETURN_VALUE_USED(opline) ? jit_ZVAL_ADDR(jit, res_addr) : IR_NULL); if ((opline+1)->op1_type == IS_CONST) { @@ -14344,7 +14365,7 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, } if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) { - if (opline->result_type == IS_UNUSED) { + if (Z_MODE(val_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,15 +14386,27 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, } if (slow_inputs) { + ir_ref arg3; + 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); + } + // 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); @@ -14412,6 +14445,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 +14458,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; @@ -16692,7 +16725,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') { diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index fb19f192a3524..24829f1963b81 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -4851,7 +4851,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 +4934,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(&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(), op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce, val_type, zend_may_throw(opline, ssa_op, op_array, ssa))) { From 639c8508e233c3c082304cf232faad0ee7253329 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 23 May 2024 15:59:39 +0300 Subject: [PATCH 2/4] Fix tests failures --- ext/opcache/jit/zend_jit_ir.c | 55 ++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 59533c60db58d..b8207d58e4184 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -14340,7 +14340,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; // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); jit_SET_EX_OPLINE(jit, opline); @@ -14354,10 +14354,19 @@ 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); + } ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop), prop_ref, ref, - jit_ZVAL_ADDR(jit, val_addr), + arg3, RETURN_VALUE_USED(opline) ? jit_ZVAL_ADDR(jit, res_addr) : IR_NULL); ir_END_list(end_inputs); @@ -14612,12 +14621,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(); @@ -14632,7 +14651,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); @@ -14656,7 +14675,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); @@ -14680,7 +14699,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; @@ -14698,9 +14717,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); @@ -14793,16 +14821,27 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit, } 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)); From 22f4308b57f89925a6ed7c1c09c17d6dfe523beb Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 23 May 2024 17:00:00 +0300 Subject: [PATCH 3/4] Fix tests failures --- ext/opcache/jit/zend_jit.c | 1 + ext/opcache/jit/zend_jit_ir.c | 68 ++++++++++++++++++++++++++------ ext/opcache/jit/zend_jit_trace.c | 1 + 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 6c226cd6c9b01..9f2c6ee21af6f 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -1862,6 +1862,7 @@ 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_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; diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index b8207d58e4184..25ed46a5e8365 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -14145,6 +14145,7 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, 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, @@ -14157,13 +14158,13 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, zval *member; zend_string *name; zend_property_info *prop_info; - 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 (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)) { @@ -14174,10 +14175,6 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, } } - if (RETURN_VALUE_USED(opline)) { - res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - } - ZEND_ASSERT(opline->op2_type == IS_CONST); ZEND_ASSERT(op1_info & MAY_BE_OBJECT); @@ -14216,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); } @@ -14286,7 +14283,7 @@ 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; + 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); @@ -14302,13 +14299,21 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, 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, arg3, - RETURN_VALUE_USED(opline) ? jit_ZVAL_ADDR(jit, res_addr) : IR_NULL); + arg4); if ((opline+1)->op1_type == IS_CONST) { // TODO: ??? @@ -14316,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); } @@ -14340,7 +14352,7 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, } } if (ZEND_TYPE_IS_SET(prop_info->type)) { - ir_ref ref, arg3; + 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); @@ -14363,18 +14375,34 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, } 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, arg3, - RETURN_VALUE_USED(opline) ? jit_ZVAL_ADDR(jit, res_addr) : IR_NULL); + 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 (Z_MODE(val_addr) != IS_REG && 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; } @@ -14395,7 +14423,7 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, } if (slow_inputs) { - ir_ref arg3; + ir_ref arg3, arg5; ir_MERGE_list(slow_inputs); jit_SET_EX_OPLINE(jit, opline); @@ -14409,6 +14437,14 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, } 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)); @@ -14417,8 +14453,14 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit, ir_CONST_ADDR(name), 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); } diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 24829f1963b81..49478241d9a0a 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -4935,6 +4935,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par 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_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))) { From dd308d0e512ce584ed4b6450e455ed59118e8b79 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 23 May 2024 18:21:52 +0300 Subject: [PATCH 4/4] Add missing GUARD --- ext/opcache/jit/zend_jit_trace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 49478241d9a0a..ece08045a5592 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -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) {