JIT for ASSIGN_OBJ

This commit is contained in:
Dmitry Stogov 2020-09-10 23:41:50 +03:00
parent e9b47df14f
commit 7b0a053169
7 changed files with 518 additions and 31 deletions

View File

@ -919,7 +919,7 @@ static zend_always_inline zend_bool i_zend_verify_property_type(zend_property_in
return 0;
}
zend_bool zend_never_inline zend_verify_property_type(zend_property_info *info, zval *property, zend_bool strict) {
ZEND_API zend_bool zend_never_inline zend_verify_property_type(zend_property_info *info, zval *property, zend_bool strict) {
return i_zend_verify_property_type(info, property, strict);
}

View File

@ -418,7 +418,7 @@ ZEND_API int ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *call);
#define ZEND_CLASS_HAS_TYPE_HINTS(ce) ((ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) == ZEND_ACC_HAS_TYPE_HINTS)
zend_bool zend_verify_property_type(zend_property_info *info, zval *property, zend_bool strict);
ZEND_API zend_bool zend_verify_property_type(zend_property_info *info, zval *property, zend_bool strict);
ZEND_COLD void zend_verify_property_type_error(zend_property_info *info, zval *property);
#define ZEND_REF_ADD_TYPE_SOURCE(ref, source) \

View File

@ -2457,6 +2457,49 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
goto jit_failure;
}
goto done;
case ZEND_ASSIGN_OBJ:
if (opline->op1_type == IS_VAR) {
break;
}
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;
}
if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
break;
}
ce = NULL;
ce_is_instanceof = 0;
if (opline->op1_type == IS_UNUSED) {
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
ce = op_array->scope;
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
op1_addr = 0;
} 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) {
zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
if (op1_ssa->ce && !op1_ssa->ce->create_object) {
ce = op1_ssa->ce;
ce_is_instanceof = op1_ssa->is_instanceof;
}
}
}
}
if (!zend_jit_assign_obj(&dasm_state, opline, op_array, ssa, ssa_op,
op1_info, op1_addr, OP1_DATA_INFO(),
0, ce, ce_is_instanceof, 0, NULL,
zend_may_throw(opline, ssa_op, op_array, ssa))) {
goto jit_failure;
}
goto done;
case ZEND_ASSIGN:
if (opline->op1_type != IS_CV) {
break;

View File

@ -456,6 +456,7 @@ static int zend_jit_disasm_init(void)
REGISTER_HELPER(zend_jit_invalid_array_access);
REGISTER_HELPER(zend_jit_invalid_property_read);
REGISTER_HELPER(zend_jit_invalid_property_write);
REGISTER_HELPER(zend_jit_invalid_property_assign);
REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
REGISTER_HELPER(zend_jit_pre_inc);
REGISTER_HELPER(zend_jit_pre_dec);
@ -466,6 +467,8 @@ static int zend_jit_disasm_init(void)
REGISTER_HELPER(zend_jit_array_free);
REGISTER_HELPER(zend_jit_zval_array_dup);
REGISTER_HELPER(zend_jit_add_arrays_helper);
REGISTER_HELPER(zend_jit_assign_obj_helper);
REGISTER_HELPER(zend_jit_assign_to_typed_prop);
#undef REGISTER_HELPER
#ifndef _WIN32

View File

@ -1858,6 +1858,13 @@ static void ZEND_FASTCALL zend_jit_invalid_property_write(zval *container, const
property_name, zend_zval_type_name(container));
}
static void ZEND_FASTCALL zend_jit_invalid_property_assign(zval *container, const char *property_name)
{
zend_throw_error(NULL,
"Attempt to assign property \"%s\" on %s",
property_name, zend_zval_type_name(container));
}
static zval * ZEND_FASTCALL zend_jit_prepare_assign_dim_ref(zval *ref) {
zval *val = Z_REFVAL_P(ref);
if (Z_TYPE_P(val) <= IS_FALSE) {
@ -1927,3 +1934,34 @@ static zend_array *ZEND_FASTCALL zend_jit_add_arrays_helper(zend_array *op1, zen
zend_hash_merge(res, op2, zval_add_ref, 0);
return res;
}
static void ZEND_FASTCALL zend_jit_assign_obj_helper(zend_object *zobj, zend_string *name, zval *value, void **cache_slot, zval *result)
{
ZVAL_DEREF(value);
value = zobj->handlers->write_property(zobj, name, value, cache_slot);
if (result) {
ZVAL_COPY_DEREF(result, value);
}
}
static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend_property_info *info, zval *value, zval *result)
{
zend_execute_data *execute_data = EG(current_execute_data);
zval tmp;
ZVAL_DEREF(value);
ZVAL_COPY(&tmp, value);
if (UNEXPECTED(!zend_verify_property_type(info, &tmp, EX_USES_STRICT_TYPES()))) {
zval_ptr_dtor(&tmp);
if (result) {
ZVAL_NULL(result);
}
return;
}
value = zend_assign_to_variable(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES());
if (result) {
ZVAL_COPY_DEREF(result, value);
}
}

View File

@ -1426,6 +1426,15 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
ADD_OP2_TRACE_GUARD();
}
break;
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') {
break;
}
// ADD_OP1_DATA_TRACE_GUARD();
ADD_OP1_TRACE_GUARD();
break;
case ZEND_IS_EQUAL:
case ZEND_IS_NOT_EQUAL:
case ZEND_IS_SMALLER:
@ -2795,7 +2804,8 @@ static zend_bool zend_jit_may_delay_fetch_this(zend_ssa *ssa, const zend_op **ss
}
} else if (opline->opcode != ZEND_FETCH_OBJ_R
&& opline->opcode != ZEND_FETCH_OBJ_IS
&& opline->opcode != ZEND_FETCH_OBJ_W) {
&& opline->opcode != ZEND_FETCH_OBJ_W
&& opline->opcode != ZEND_ASSIGN_OBJ) {
return 0;
}
@ -3708,6 +3718,72 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
goto jit_failure;
}
goto done;
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') {
break;
}
ce = NULL;
ce_is_instanceof = 0;
delayed_fetch_this = 0;
op1_indirect = 0;
if (opline->op1_type == IS_UNUSED) {
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
ce = op_array->scope;
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
op1_addr = 0;
} else {
if (ssa_op->op1_use >= 0) {
delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
}
op1_info = OP1_INFO();
if (!(op1_info & MAY_BE_OBJECT)) {
break;
}
op1_addr = OP1_REG_ADDR();
if (opline->op1_type == IS_VAR) {
if (orig_op1_type != IS_UNKNOWN
&& (orig_op1_type & IS_TRACE_INDIRECT)) {
op1_indirect = 1;
if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
&op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
goto jit_failure;
}
}
}
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,
!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
goto jit_failure;
}
if (opline->op1_type == IS_CV
&& zend_jit_var_may_alias(op_array, op_array_ssa, EX_VAR_TO_NUM(opline->op1.var)) == NO_ALIAS) {
ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
}
} 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;
if (op1_ssa->ce && !op1_ssa->ce->create_object) {
ce = op1_ssa->ce;
ce_is_instanceof = op1_ssa->is_instanceof;
}
}
}
}
op1_data_info = OP1_DATA_INFO();
CHECK_OP1_DATA_TRACE_TYPE();
if (!zend_jit_assign_obj(&dasm_state, opline, op_array, ssa, ssa_op,
op1_info, op1_addr, op1_data_info,
op1_indirect, ce, ce_is_instanceof, delayed_fetch_this, op1_ce,
zend_may_throw(opline, ssa_op, op_array, ssa))) {
goto jit_failure;
}
goto done;
case ZEND_ASSIGN_DIM:
op1_info = OP1_INFO();
op1_addr = OP1_REG_ADDR();

View File

@ -5848,6 +5848,52 @@ static int zend_jit_assign_to_typed_ref(dasm_State **Dst,
return 1;
}
static int zend_jit_assign_to_variable_call(dasm_State **Dst,
const zend_op *opline,
zend_jit_addr __var_use_addr,
zend_jit_addr var_addr,
uint32_t __var_info,
uint32_t __var_def_info,
zend_uchar val_type,
zend_jit_addr val_addr,
uint32_t val_info,
zend_jit_addr __res_addr,
zend_bool __check_exception)
{
if (Z_MODE(var_addr) != IS_MEM_ZVAL || Z_REG(var_addr) != ZREG_FCARG1a || Z_OFFSET(var_addr) != 0) {
| LOAD_ZVAL_ADDR FCARG1a, var_addr
}
if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2a || Z_OFFSET(val_addr) != 0) {
| LOAD_ZVAL_ADDR FCARG2a, val_addr
}
if (opline) {
| SET_EX_OPLINE opline, r0
}
if (!(val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
| call ->assign_tmp
} else if (val_type == IS_CONST) {
| call ->assign_const
} else if (val_type == IS_TMP_VAR) {
| call ->assign_tmp
} else if (val_type == IS_VAR) {
if (!(val_info & MAY_BE_REF)) {
| call ->assign_tmp
} else {
| call ->assign_var
}
} else if (val_type == IS_CV) {
if (!(val_info & MAY_BE_REF)) {
| call ->assign_cv_noref
} else {
| call ->assign_cv
}
} else {
ZEND_UNREACHABLE();
}
return 1;
}
static int zend_jit_assign_to_variable(dasm_State **Dst,
const zend_op *opline,
zend_jit_addr var_use_addr,
@ -6114,36 +6160,13 @@ static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, uint32_t
| // value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
if (opline->op1_type == IS_VAR) {
ZEND_ASSERT(opline->result_type == IS_UNUSED);
if (Z_MODE(var_addr) != IS_MEM_ZVAL || Z_REG(var_addr) != ZREG_FCARG1a || Z_OFFSET(var_addr) != 0) {
| LOAD_ZVAL_ADDR FCARG1a, var_addr
if (!zend_jit_assign_to_variable_call(Dst, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
return 0;
}
if (Z_MODE(op3_addr) != IS_MEM_ZVAL || Z_REG(op3_addr) != ZREG_FCARG2a || Z_OFFSET(op3_addr) != 0) {
| LOAD_ZVAL_ADDR FCARG2a, op3_addr
} else {
if (!zend_jit_assign_to_variable(Dst, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
return 0;
}
| SET_EX_OPLINE opline, r0
if (!(val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
| call ->assign_tmp
} else if ((opline+1)->op1_type == IS_CONST) {
| call ->assign_const
} else if ((opline+1)->op1_type == IS_TMP_VAR) {
| call ->assign_tmp
} else if ((opline+1)->op1_type == IS_VAR) {
if (!(val_info & MAY_BE_REF)) {
| call ->assign_tmp
} else {
| call ->assign_var
}
} else if ((opline+1)->op1_type == IS_CV) {
if (!(val_info & MAY_BE_REF)) {
| call ->assign_cv_noref
} else {
| call ->assign_cv
}
} else {
ZEND_UNREACHABLE();
}
} else if (!zend_jit_assign_to_variable(Dst, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
return 0;
}
}
}
@ -12277,6 +12300,310 @@ static int zend_jit_fetch_obj(dasm_State **Dst,
return 1;
}
static int zend_jit_assign_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,
uint32_t val_info,
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_string *name;
zend_property_info *prop_info;
zend_jit_addr val_addr = OP1_DATA_ADDR();
zend_jit_addr res_addr = 0;
zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
zend_jit_addr prop_addr;
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);
member = RT_CONSTANT(opline, opline->op2);
ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
name = Z_STR_P(member);
prop_info = zend_get_known_property_info(ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
if (opline->op1_type == IS_UNUSED || use_this) {
| GET_ZVAL_PTR FCARG1a, this_addr
} else {
if (opline->op1_type == IS_VAR
&& (op1_info & MAY_BE_INDIRECT)
&& Z_REG(op1_addr) == ZREG_FP) {
| LOAD_ZVAL_ADDR FCARG1a, op1_addr
| IF_NOT_Z_TYPE FCARG1a, IS_INDIRECT, >1
| GET_Z_PTR FCARG1a, FCARG1a
|1:
op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
}
if (op1_info & MAY_BE_REF) {
if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 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) {
int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
if (!exit_addr) {
return 0;
}
| IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr
} else {
| IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1
|.cold_code
|1:
| SET_EX_OPLINE opline, r0
if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
| LOAD_ZVAL_ADDR FCARG1a, op1_addr
}
| LOAD_ADDR FCARG2a, ZSTR_VAL(name)
| EXT_CALL zend_jit_invalid_property_assign, r0
if (RETURN_VALUE_USED(opline)) {
| SET_ZVAL_TYPE_INFO res_addr, IS_NULL
}
if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
&& (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
| jmp >8
} else {
| jmp ->exception_handler
}
|.code
}
}
| 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, name, opline->op1_type == IS_UNUSED, op_array->filename);
if (prop_info) {
ce = trace_ce;
ce_is_instanceof = 0;
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]
| cmp r2, aword [FCARG1a + offsetof(zend_object, ce)]
| jne >5
if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
| mov FCARG2a, aword [r0 + (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2]
}
| mov r0, aword [r0 + opline->extended_value + sizeof(void*)]
| test r0, r0
| jl >5
| IF_TYPE byte [FCARG1a + r0 + 8], IS_UNDEF, >5
| add FCARG1a, r0
prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
| test FCARG2a, FCARG2a
| jnz >1
|.cold_code
|1:
| // value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
| SET_EX_OPLINE opline, r0
|.if X64
| LOAD_ZVAL_ADDR CARG3, val_addr
if (RETURN_VALUE_USED(opline)) {
| LOAD_ZVAL_ADDR CARG4, res_addr
} else {
| xor CARG4, CARG4
}
|.else
| sub r4, 8
if (RETURN_VALUE_USED(opline)) {
| PUSH_ZVAL_ADDR res_addr, r0
} else {
| push 0
}
| PUSH_ZVAL_ADDR val_addr, r0
|.endif
| EXT_CALL zend_jit_assign_to_typed_prop, r0
|.if not(X64)
| add r4, 8
|.endif
if ((opline+1)->op1_type == IS_CONST) {
| // TODO: ???
| // if (Z_TYPE_P(value) == orig_type) {
| // CACHE_PTR_EX(cache_slot + 2, NULL);
}
if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
&& (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
| jmp >8
} else {
| jmp >9
}
|.code
}
} else {
prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, prop_info->offset);
// Undefined property with magic __get()/__set()
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
if (!exit_addr) {
return 0;
}
| IF_TYPE byte [FCARG1a + prop_info->offset + 8], IS_UNDEF, &exit_addr
} else {
| IF_TYPE byte [FCARG1a + prop_info->offset + 8], IS_UNDEF, >5
}
if (ZEND_TYPE_IS_SET(prop_info->type)) {
uint32_t info = val_info;
| // value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
| SET_EX_OPLINE opline, r0
if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
| LOAD_ADDR FCARG2a, prop_info
} else {
int prop_info_offset =
(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
| mov r0, aword [FCARG1a + offsetof(zend_object, ce)]
| mov r0, aword [r0 + offsetof(zend_class_entry, properties_info_table)]
| mov FCARG2a, aword[r0 + prop_info_offset]
}
| LOAD_ZVAL_ADDR FCARG1a, prop_addr
|.if X64
| LOAD_ZVAL_ADDR CARG3, val_addr
if (RETURN_VALUE_USED(opline)) {
| LOAD_ZVAL_ADDR CARG4, res_addr
} else {
| xor CARG4, CARG4
}
|.else
| sub r4, 8
if (RETURN_VALUE_USED(opline)) {
| PUSH_ZVAL_ADDR res_addr, r0
} else {
| push 0
}
| PUSH_ZVAL_ADDR val_addr, r0
|.endif
| EXT_CALL zend_jit_assign_to_typed_prop, r0
|.if not(X64)
| add r4, 8
|.endif
if (info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
info |= MAY_BE_RC1|MAY_BE_RCN;
}
| FREE_OP (opline+1)->op1_type, (opline+1)->op1, info, 0, opline
}
}
if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
// value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES());
if (opline->result_type == IS_UNUSED) {
if (!zend_jit_assign_to_variable_call(Dst, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) {
return 0;
}
} else {
if (!zend_jit_assign_to_variable(Dst, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) {
return 0;
}
}
}
if (!prop_info || JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
|.cold_code
|5:
| SET_EX_OPLINE opline, r0
| // value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
| LOAD_ADDR FCARG2a, name
|.if X64
| LOAD_ZVAL_ADDR CARG3, val_addr
| mov CARG4, EX->run_time_cache
| add CARG4, opline->extended_value
if (RETURN_VALUE_USED(opline)) {
|.if X64WIN
| LOAD_ZVAL_ADDR r0, res_addr
| mov aword A5, r0
|.else
| LOAD_ZVAL_ADDR CARG5, res_addr
|.endif
} else {
|.if X64WIN
| mov aword A5, 0
|.else
| xor CARG5, CARG5
|.endif
}
|.else
| sub r4, 4
if (RETURN_VALUE_USED(opline)) {
| PUSH_ZVAL_ADDR res_addr, r0
} else {
| push 0
}
| mov r0, EX->run_time_cache
| add r0, opline->extended_value
| push r0
| PUSH_ZVAL_ADDR val_addr, r0
|.endif
| EXT_CALL zend_jit_assign_obj_helper, r0
|.if not(X64)
| add r4, 4
|.endif
if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
val_info |= MAY_BE_RC1|MAY_BE_RCN;
}
|8:
| // FREE_OP_DATA();
| FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, opline
| jmp >9
|.code
}
|9:
if (opline->op1_type != IS_UNUSED && !use_this && !op1_indirect) {
| FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
}
if (may_throw) {
if (!zend_jit_check_exception(Dst)) {
return 0;
}
}
return 1;
}
static int zend_jit_free(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, int may_throw)
{
zend_jit_addr op1_addr = OP1_ADDR();