mirror of
https://github.com/php/php-src.git
synced 2026-04-26 01:18:19 +02:00
JIT for PRE/POST_INC/DEC_OBJ
This commit is contained in:
@@ -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_PRE_INC_OBJ:
|
||||
case ZEND_PRE_DEC_OBJ:
|
||||
case ZEND_POST_INC_OBJ:
|
||||
case ZEND_POST_DEC_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;
|
||||
}
|
||||
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_incdec_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;
|
||||
}
|
||||
goto done;
|
||||
case ZEND_ASSIGN_OBJ_OP:
|
||||
if (opline->extended_value == ZEND_POW
|
||||
|| opline->extended_value == ZEND_DIV) {
|
||||
|
||||
@@ -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_incdec);
|
||||
REGISTER_HELPER(zend_jit_invalid_property_assign);
|
||||
REGISTER_HELPER(zend_jit_invalid_property_assign_op);
|
||||
REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
|
||||
@@ -472,6 +473,16 @@ static int zend_jit_disasm_init(void)
|
||||
REGISTER_HELPER(zend_jit_assign_obj_op_helper);
|
||||
REGISTER_HELPER(zend_jit_assign_to_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_inc_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_dec_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_post_inc_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_post_dec_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_post_inc_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_post_dec_obj_helper);
|
||||
#undef REGISTER_HELPER
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
@@ -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_incdec(zval *container, const char *property_name)
|
||||
{
|
||||
zend_throw_error(NULL,
|
||||
"Attempt to increment/decrement property \"%s\" on %s",
|
||||
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,
|
||||
@@ -2060,3 +2067,425 @@ static void ZEND_FASTCALL zend_jit_assign_obj_op_helper(zend_object *zobj, zend_
|
||||
_zend_jit_assign_op_overloaded_property(zobj, name, cache_slot, value, binary_op);
|
||||
}
|
||||
}
|
||||
|
||||
static ZEND_COLD zend_long _zend_jit_throw_inc_prop_error(zend_property_info *prop)
|
||||
{
|
||||
zend_string *type_str = zend_type_to_string(prop->type);
|
||||
zend_type_error("Cannot increment property %s::$%s of type %s past its maximal value",
|
||||
ZSTR_VAL(prop->ce->name),
|
||||
zend_get_unmangled_property_name(prop->name),
|
||||
ZSTR_VAL(type_str));
|
||||
zend_string_release(type_str);
|
||||
return ZEND_LONG_MAX;
|
||||
}
|
||||
|
||||
static ZEND_COLD zend_long _zend_jit_throw_dec_prop_error(zend_property_info *prop)
|
||||
{
|
||||
zend_string *type_str = zend_type_to_string(prop->type);
|
||||
zend_type_error("Cannot decrement property %s::$%s of type %s past its minimal value",
|
||||
ZSTR_VAL(prop->ce->name),
|
||||
zend_get_unmangled_property_name(prop->name),
|
||||
ZSTR_VAL(type_str));
|
||||
zend_string_release(type_str);
|
||||
return ZEND_LONG_MIN;
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info)
|
||||
{
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
zval tmp;
|
||||
|
||||
ZVAL_COPY(&tmp, var_ptr);
|
||||
|
||||
increment_function(var_ptr);
|
||||
|
||||
if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
|
||||
if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
|
||||
zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
|
||||
ZVAL_LONG(var_ptr, val);
|
||||
}
|
||||
} else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
|
||||
zval_ptr_dtor(var_ptr);
|
||||
ZVAL_COPY_VALUE(var_ptr, &tmp);
|
||||
} else {
|
||||
zval_ptr_dtor(&tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info)
|
||||
{
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
zval tmp;
|
||||
|
||||
ZVAL_COPY(&tmp, var_ptr);
|
||||
|
||||
decrement_function(var_ptr);
|
||||
|
||||
if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
|
||||
if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
|
||||
zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
|
||||
ZVAL_LONG(var_ptr, val);
|
||||
}
|
||||
} else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
|
||||
zval_ptr_dtor(var_ptr);
|
||||
ZVAL_COPY_VALUE(var_ptr, &tmp);
|
||||
} else {
|
||||
zval_ptr_dtor(&tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_pre_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
|
||||
{
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
zval tmp;
|
||||
|
||||
if (!result) {
|
||||
result = &tmp;
|
||||
}
|
||||
|
||||
ZVAL_COPY(result, var_ptr);
|
||||
|
||||
increment_function(var_ptr);
|
||||
|
||||
if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(result) == IS_LONG) {
|
||||
if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
|
||||
zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
|
||||
ZVAL_LONG(var_ptr, val);
|
||||
}
|
||||
} else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
|
||||
zval_ptr_dtor(var_ptr);
|
||||
ZVAL_COPY_VALUE(var_ptr, result);
|
||||
ZVAL_UNDEF(result);
|
||||
} else if (result == &tmp) {
|
||||
zval_ptr_dtor(&tmp);
|
||||
}
|
||||
if (UNEXPECTED(result)) {
|
||||
ZVAL_COPY(result, var_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_pre_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
|
||||
{
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
zval tmp;
|
||||
|
||||
if (!result) {
|
||||
result = &tmp;
|
||||
}
|
||||
|
||||
ZVAL_COPY(result, var_ptr);
|
||||
|
||||
decrement_function(var_ptr);
|
||||
|
||||
if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(result) == IS_LONG) {
|
||||
if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
|
||||
zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
|
||||
ZVAL_LONG(var_ptr, val);
|
||||
}
|
||||
} else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
|
||||
zval_ptr_dtor(var_ptr);
|
||||
ZVAL_COPY_VALUE(var_ptr, result);
|
||||
ZVAL_UNDEF(result);
|
||||
} else if (result == &tmp) {
|
||||
zval_ptr_dtor(&tmp);
|
||||
}
|
||||
if (UNEXPECTED(result)) {
|
||||
ZVAL_COPY(result, var_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_post_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
|
||||
{
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
|
||||
ZVAL_COPY(result, var_ptr);
|
||||
|
||||
increment_function(var_ptr);
|
||||
|
||||
if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(result) == IS_LONG) {
|
||||
if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
|
||||
zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
|
||||
ZVAL_LONG(var_ptr, val);
|
||||
}
|
||||
} else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
|
||||
zval_ptr_dtor(var_ptr);
|
||||
ZVAL_COPY_VALUE(var_ptr, result);
|
||||
ZVAL_UNDEF(result);
|
||||
}
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_post_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
|
||||
{
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
|
||||
ZVAL_COPY(result, var_ptr);
|
||||
|
||||
decrement_function(var_ptr);
|
||||
|
||||
if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(result) == IS_LONG) {
|
||||
if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
|
||||
zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
|
||||
ZVAL_LONG(var_ptr, val);
|
||||
}
|
||||
} else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
|
||||
zval_ptr_dtor(var_ptr);
|
||||
ZVAL_COPY_VALUE(var_ptr, result);
|
||||
ZVAL_UNDEF(result);
|
||||
}
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_pre_inc_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
|
||||
{
|
||||
zval *prop;
|
||||
|
||||
if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
|
||||
if (UNEXPECTED(Z_ISERROR_P(prop))) {
|
||||
if (UNEXPECTED(result)) {
|
||||
ZVAL_NULL(result);
|
||||
}
|
||||
} else {
|
||||
zend_property_info *prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2);
|
||||
|
||||
if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
|
||||
fast_long_increment_function(prop);
|
||||
if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && UNEXPECTED(prop_info)
|
||||
&& !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
|
||||
zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
|
||||
ZVAL_LONG(prop, val);
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
if (Z_ISREF_P(prop)) {
|
||||
zend_reference *ref = Z_REF_P(prop);
|
||||
prop = Z_REFVAL_P(prop);
|
||||
if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
|
||||
zend_jit_pre_inc_typed_ref(&ref->val, ref, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (UNEXPECTED(prop_info)) {
|
||||
zend_jit_pre_inc_typed_prop(prop, prop_info, result);
|
||||
return;
|
||||
} else {
|
||||
increment_function(prop);
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
if (UNEXPECTED(result)) {
|
||||
ZVAL_COPY(result, prop);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zval rv;
|
||||
zval *z;
|
||||
zval z_copy;
|
||||
|
||||
GC_ADDREF(zobj);
|
||||
z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
OBJ_RELEASE(zobj);
|
||||
if (UNEXPECTED(result)) {
|
||||
ZVAL_NULL(result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ZVAL_COPY_DEREF(&z_copy, z);
|
||||
increment_function(&z_copy);
|
||||
if (UNEXPECTED(result)) {
|
||||
ZVAL_COPY(result, &z_copy);
|
||||
}
|
||||
zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
|
||||
OBJ_RELEASE(zobj);
|
||||
zval_ptr_dtor(&z_copy);
|
||||
zval_ptr_dtor(z);
|
||||
}
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_pre_dec_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
|
||||
{
|
||||
zval *prop;
|
||||
|
||||
if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
|
||||
if (UNEXPECTED(Z_ISERROR_P(prop))) {
|
||||
if (UNEXPECTED(result)) {
|
||||
ZVAL_NULL(result);
|
||||
}
|
||||
} else {
|
||||
zend_property_info *prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2);
|
||||
|
||||
if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
|
||||
fast_long_decrement_function(prop);
|
||||
if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && UNEXPECTED(prop_info)
|
||||
&& !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
|
||||
zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
|
||||
ZVAL_LONG(prop, val);
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
if (Z_ISREF_P(prop)) {
|
||||
zend_reference *ref = Z_REF_P(prop);
|
||||
prop = Z_REFVAL_P(prop);
|
||||
if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
|
||||
zend_jit_pre_dec_typed_ref(&ref->val, ref, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (UNEXPECTED(prop_info)) {
|
||||
zend_jit_pre_dec_typed_prop(prop, prop_info, result);
|
||||
return;
|
||||
} else {
|
||||
decrement_function(prop);
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
if (UNEXPECTED(result)) {
|
||||
ZVAL_COPY(result, prop);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zval rv;
|
||||
zval *z;
|
||||
zval z_copy;
|
||||
|
||||
GC_ADDREF(zobj);
|
||||
z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
OBJ_RELEASE(zobj);
|
||||
if (UNEXPECTED(result)) {
|
||||
ZVAL_NULL(result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ZVAL_COPY_DEREF(&z_copy, z);
|
||||
decrement_function(&z_copy);
|
||||
if (UNEXPECTED(result)) {
|
||||
ZVAL_COPY(result, &z_copy);
|
||||
}
|
||||
zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
|
||||
OBJ_RELEASE(zobj);
|
||||
zval_ptr_dtor(&z_copy);
|
||||
zval_ptr_dtor(z);
|
||||
}
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_post_inc_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
|
||||
{
|
||||
zval *prop;
|
||||
|
||||
if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
|
||||
if (UNEXPECTED(Z_ISERROR_P(prop))) {
|
||||
ZVAL_NULL(result);
|
||||
} else {
|
||||
zend_property_info *prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2);
|
||||
|
||||
if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
|
||||
ZVAL_LONG(result, Z_LVAL_P(prop));
|
||||
fast_long_increment_function(prop);
|
||||
if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && UNEXPECTED(prop_info)
|
||||
&& !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
|
||||
zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
|
||||
ZVAL_LONG(prop, val);
|
||||
}
|
||||
} else {
|
||||
if (Z_ISREF_P(prop)) {
|
||||
zend_reference *ref = Z_REF_P(prop);
|
||||
prop = Z_REFVAL_P(prop);
|
||||
if (ZEND_REF_HAS_TYPE_SOURCES(ref)) {
|
||||
zend_jit_post_inc_typed_ref(&ref->val, ref, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (UNEXPECTED(prop_info)) {
|
||||
zend_jit_post_inc_typed_prop(prop, prop_info, result);
|
||||
} else {
|
||||
ZVAL_COPY(result, prop);
|
||||
increment_function(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zval rv;
|
||||
zval *z;
|
||||
zval z_copy;
|
||||
|
||||
GC_ADDREF(zobj);
|
||||
z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
OBJ_RELEASE(zobj);
|
||||
ZVAL_UNDEF(result);
|
||||
return;
|
||||
}
|
||||
|
||||
ZVAL_COPY_DEREF(&z_copy, z);
|
||||
ZVAL_COPY(result, &z_copy);
|
||||
increment_function(&z_copy);
|
||||
zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
|
||||
OBJ_RELEASE(zobj);
|
||||
zval_ptr_dtor(&z_copy);
|
||||
zval_ptr_dtor(z);
|
||||
}
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_post_dec_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
|
||||
{
|
||||
zval *prop;
|
||||
|
||||
if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
|
||||
if (UNEXPECTED(Z_ISERROR_P(prop))) {
|
||||
ZVAL_NULL(result);
|
||||
} else {
|
||||
zend_property_info *prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2);
|
||||
|
||||
if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
|
||||
ZVAL_LONG(result, Z_LVAL_P(prop));
|
||||
fast_long_decrement_function(prop);
|
||||
if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && UNEXPECTED(prop_info)
|
||||
&& !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
|
||||
zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
|
||||
ZVAL_LONG(prop, val);
|
||||
}
|
||||
} else {
|
||||
if (Z_ISREF_P(prop)) {
|
||||
zend_reference *ref = Z_REF_P(prop);
|
||||
prop = Z_REFVAL_P(prop);
|
||||
if (ZEND_REF_HAS_TYPE_SOURCES(ref)) {
|
||||
zend_jit_post_dec_typed_ref(&ref->val, ref, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (UNEXPECTED(prop_info)) {
|
||||
zend_jit_post_dec_typed_prop(prop, prop_info, result);
|
||||
} else {
|
||||
ZVAL_COPY(result, prop);
|
||||
decrement_function(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zval rv;
|
||||
zval *z;
|
||||
zval z_copy;
|
||||
|
||||
GC_ADDREF(zobj);
|
||||
z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
OBJ_RELEASE(zobj);
|
||||
ZVAL_UNDEF(result);
|
||||
return;
|
||||
}
|
||||
|
||||
ZVAL_COPY_DEREF(&z_copy, z);
|
||||
ZVAL_COPY(result, &z_copy);
|
||||
decrement_function(&z_copy);
|
||||
zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
|
||||
OBJ_RELEASE(zobj);
|
||||
zval_ptr_dtor(&z_copy);
|
||||
zval_ptr_dtor(z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1439,6 +1439,10 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
|
||||
}
|
||||
/* break missing intentionally */
|
||||
case ZEND_ASSIGN_OBJ:
|
||||
case ZEND_PRE_INC_OBJ:
|
||||
case ZEND_PRE_DEC_OBJ:
|
||||
case ZEND_POST_INC_OBJ:
|
||||
case ZEND_POST_DEC_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') {
|
||||
@@ -3732,6 +3736,73 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
goto jit_failure;
|
||||
}
|
||||
goto done;
|
||||
case ZEND_PRE_INC_OBJ:
|
||||
case ZEND_PRE_DEC_OBJ:
|
||||
case ZEND_POST_INC_OBJ:
|
||||
case ZEND_POST_DEC_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!zend_jit_incdec_obj(&dasm_state, opline, op_array, ssa, ssa_op,
|
||||
op1_info, op1_addr,
|
||||
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_OBJ_OP:
|
||||
if (opline->extended_value == ZEND_POW
|
||||
|| opline->extended_value == ZEND_DIV) {
|
||||
|
||||
@@ -12324,6 +12324,393 @@ static int zend_jit_fetch_obj(dasm_State **Dst,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int zend_jit_incdec_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_string *name;
|
||||
zend_property_info *prop_info;
|
||||
zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
|
||||
zend_jit_addr res_addr = 0;
|
||||
zend_jit_addr prop_addr;
|
||||
zend_bool needs_slow_path = 0;
|
||||
|
||||
ZEND_ASSERT(opline->op2_type == IS_CONST);
|
||||
ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
|
||||
|
||||
if (opline->result_type != IS_UNUSED) {
|
||||
res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
|
||||
}
|
||||
|
||||
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_incdec, r0
|
||||
| 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;
|
||||
ssa->var_info[ssa_op->op1_use].ce = ce;
|
||||
ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
|
||||
}
|
||||
if (ssa->var_info && ssa_op->op1_def >= 0) {
|
||||
ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
|
||||
ssa->var_info[ssa_op->op1_def].ce = ce;
|
||||
ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!prop_info) {
|
||||
needs_slow_path = 1;
|
||||
|
||||
| mov r0, EX->run_time_cache
|
||||
| mov r2, aword [r0 + opline->extended_value]
|
||||
| cmp r2, aword [FCARG1a + offsetof(zend_object, ce)]
|
||||
| jne >7
|
||||
if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
|
||||
| cmp aword [r0 + opline->extended_value + sizeof(void*) * 2], 0
|
||||
| jnz >7
|
||||
}
|
||||
| mov r0, aword [r0 + opline->extended_value + sizeof(void*)]
|
||||
| test r0, r0
|
||||
| jl >7
|
||||
| IF_TYPE byte [FCARG1a + r0 + 8], IS_UNDEF, >7
|
||||
| add FCARG1a, r0
|
||||
prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
|
||||
} else {
|
||||
prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, prop_info->offset);
|
||||
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, >7
|
||||
needs_slow_path = 1;
|
||||
}
|
||||
if (ZEND_TYPE_IS_SET(prop_info->type)) {
|
||||
| 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 (opline->result_type == IS_UNUSED) {
|
||||
switch (opline->opcode) {
|
||||
case ZEND_PRE_INC_OBJ:
|
||||
case ZEND_POST_INC_OBJ:
|
||||
| EXT_CALL zend_jit_inc_typed_prop, r0
|
||||
break;
|
||||
case ZEND_PRE_DEC_OBJ:
|
||||
case ZEND_POST_DEC_OBJ:
|
||||
| EXT_CALL zend_jit_dec_typed_prop, r0
|
||||
break;
|
||||
default:
|
||||
ZEND_UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
|.if X64
|
||||
| LOAD_ZVAL_ADDR CARG3, res_addr
|
||||
|.else
|
||||
| sub r4, 12
|
||||
| PUSH_ZVAL_ADDR res_addr, r0
|
||||
|.endif
|
||||
switch (opline->opcode) {
|
||||
case ZEND_PRE_INC_OBJ:
|
||||
| EXT_CALL zend_jit_pre_inc_typed_prop, r0
|
||||
break;
|
||||
case ZEND_PRE_DEC_OBJ:
|
||||
| EXT_CALL zend_jit_pre_dec_typed_prop, r0
|
||||
break;
|
||||
case ZEND_POST_INC_OBJ:
|
||||
| EXT_CALL zend_jit_post_inc_typed_prop, r0
|
||||
break;
|
||||
case ZEND_POST_DEC_OBJ:
|
||||
| EXT_CALL zend_jit_post_dec_typed_prop, r0
|
||||
break;
|
||||
default:
|
||||
ZEND_UNREACHABLE();
|
||||
}
|
||||
|.if not(X64)
|
||||
| add r4, 12
|
||||
|.endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
|
||||
zend_jit_addr var_addr = prop_addr;
|
||||
|
||||
var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
|
||||
| LOAD_ZVAL_ADDR r0, prop_addr
|
||||
|
||||
| IF_NOT_ZVAL_TYPE var_addr, IS_REFERENCE, >2
|
||||
| GET_ZVAL_PTR FCARG2a, var_addr
|
||||
| cmp aword [FCARG2a + offsetof(zend_reference, sources.ptr)], 0
|
||||
| jnz >1
|
||||
| lea r0, aword [FCARG2a + offsetof(zend_reference, val)]
|
||||
|.cold_code
|
||||
|1:
|
||||
| lea FCARG1a, [FCARG2a + offsetof(zend_reference, val)]
|
||||
if (opline) {
|
||||
| SET_EX_OPLINE opline, r0
|
||||
}
|
||||
|.if X64
|
||||
if (opline->result_type == IS_UNUSED) {
|
||||
| xor CARG3, CARG3
|
||||
} else {
|
||||
| LOAD_ZVAL_ADDR CARG3, res_addr
|
||||
}
|
||||
|.else
|
||||
if (opline->result_type == IS_UNUSED) {
|
||||
| push 0
|
||||
} else {
|
||||
| PUSH_ZVAL_ADDR res_addr, r0
|
||||
}
|
||||
|.endif
|
||||
switch (opline->opcode) {
|
||||
case ZEND_PRE_INC_OBJ:
|
||||
| EXT_CALL zend_jit_pre_inc_typed_ref, r0
|
||||
break;
|
||||
case ZEND_PRE_DEC_OBJ:
|
||||
| EXT_CALL zend_jit_pre_dec_typed_ref, r0
|
||||
break;
|
||||
case ZEND_POST_INC_OBJ:
|
||||
| EXT_CALL zend_jit_post_inc_typed_ref, r0
|
||||
break;
|
||||
case ZEND_POST_DEC_OBJ:
|
||||
| EXT_CALL zend_jit_post_dec_typed_ref, r0
|
||||
break;
|
||||
default:
|
||||
ZEND_UNREACHABLE();
|
||||
}
|
||||
|.if not(X64)
|
||||
| add r4, 12
|
||||
|.endif
|
||||
| jmp >9
|
||||
|.code
|
||||
|
||||
|2:
|
||||
| IF_NOT_ZVAL_TYPE var_addr, IS_LONG, >2
|
||||
if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
|
||||
if (opline->result_type != IS_UNUSED) {
|
||||
| ZVAL_COPY_VALUE res_addr, -1, var_addr, MAY_BE_LONG, ZREG_R1, ZREG_R2
|
||||
}
|
||||
}
|
||||
if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
|
||||
| LONG_OP_WITH_32BIT_CONST add, var_addr, Z_L(1)
|
||||
} else {
|
||||
| LONG_OP_WITH_32BIT_CONST sub, var_addr, Z_L(1)
|
||||
}
|
||||
| jo >3
|
||||
if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
|
||||
if (opline->result_type != IS_UNUSED) {
|
||||
| ZVAL_COPY_VALUE res_addr, -1, var_addr, MAY_BE_LONG, ZREG_R1, ZREG_R2
|
||||
}
|
||||
}
|
||||
|.cold_code
|
||||
|2:
|
||||
| LOAD_ZVAL_ADDR FCARG1a, var_addr
|
||||
if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
|
||||
zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
|
||||
|
||||
| ZVAL_COPY_VALUE res_addr, -1, val_addr, MAY_BE_ANY, ZREG_R0, ZREG_R2
|
||||
| TRY_ADDREF MAY_BE_ANY, ah, r2
|
||||
}
|
||||
if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
|
||||
if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
|
||||
| LOAD_ZVAL_ADDR FCARG2a, res_addr
|
||||
| EXT_CALL zend_jit_pre_inc, r0
|
||||
} else {
|
||||
| EXT_CALL increment_function, r0
|
||||
}
|
||||
} else {
|
||||
if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
|
||||
| LOAD_ZVAL_ADDR FCARG2a, res_addr
|
||||
| EXT_CALL zend_jit_pre_dec, r0
|
||||
} else {
|
||||
| EXT_CALL decrement_function, r0
|
||||
}
|
||||
}
|
||||
| jmp >4
|
||||
|
||||
|3:
|
||||
if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
|
||||
|.if X64
|
||||
| mov64 rax, 0x43e0000000000000
|
||||
| SET_ZVAL_LVAL var_addr, rax
|
||||
if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
|
||||
| SET_ZVAL_LVAL res_addr, rax
|
||||
}
|
||||
|.else
|
||||
| SET_ZVAL_LVAL var_addr, 0
|
||||
| SET_ZVAL_W2 var_addr, 0x41e00000
|
||||
if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
|
||||
| SET_ZVAL_LVAL res_addr, 0
|
||||
| SET_ZVAL_W2 res_addr, 0x41e00000
|
||||
}
|
||||
|.endif
|
||||
} else {
|
||||
|.if X64
|
||||
| mov64 rax, 0xc3e0000000000000
|
||||
| SET_ZVAL_LVAL var_addr, rax
|
||||
if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
|
||||
| SET_ZVAL_LVAL res_addr, rax
|
||||
}
|
||||
|.else
|
||||
| SET_ZVAL_LVAL var_addr, 0x00200000
|
||||
| SET_ZVAL_W2 var_addr, 0xc1e00000
|
||||
if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
|
||||
| SET_ZVAL_LVAL res_addr, 0x00200000
|
||||
| SET_ZVAL_W2 res_addr, 0xc1e00000
|
||||
}
|
||||
|.endif
|
||||
}
|
||||
| jmp >4
|
||||
|.code
|
||||
|4:
|
||||
}
|
||||
|
||||
if (needs_slow_path) {
|
||||
|.cold_code
|
||||
|7:
|
||||
| SET_EX_OPLINE opline, r0
|
||||
| // value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
|
||||
| LOAD_ADDR FCARG2a, name
|
||||
|.if X64
|
||||
| mov CARG3, EX->run_time_cache
|
||||
| add CARG3, opline->extended_value
|
||||
if (opline->result_type == IS_UNUSED) {
|
||||
| xor CARG4, CARG4
|
||||
} else {
|
||||
| LOAD_ZVAL_ADDR CARG4, res_addr
|
||||
}
|
||||
|.else
|
||||
| sub r4, 8
|
||||
if (opline->result_type == IS_UNUSED) {
|
||||
| push 0
|
||||
} else {
|
||||
| PUSH_ZVAL_ADDR res_addr, r0
|
||||
}
|
||||
| mov r0, EX->run_time_cache
|
||||
| add r0, opline->extended_value
|
||||
| push r0
|
||||
|.endif
|
||||
|
||||
switch (opline->opcode) {
|
||||
case ZEND_PRE_INC_OBJ:
|
||||
| EXT_CALL zend_jit_pre_inc_obj_helper, r0
|
||||
break;
|
||||
case ZEND_PRE_DEC_OBJ:
|
||||
| EXT_CALL zend_jit_pre_dec_obj_helper, r0
|
||||
break;
|
||||
case ZEND_POST_INC_OBJ:
|
||||
| EXT_CALL zend_jit_post_inc_obj_helper, r0
|
||||
break;
|
||||
case ZEND_POST_DEC_OBJ:
|
||||
| EXT_CALL zend_jit_post_dec_obj_helper, r0
|
||||
break;
|
||||
default:
|
||||
ZEND_UNREACHABLE();
|
||||
}
|
||||
|
||||
|.if not(X64)
|
||||
| add r4, 8
|
||||
|.endif
|
||||
|
||||
| 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_assign_obj_op(dasm_State **Dst,
|
||||
const zend_op *opline,
|
||||
const zend_op_array *op_array,
|
||||
|
||||
Reference in New Issue
Block a user