Reuse zend_assign_to_variable() in zend_std_write_property()

This commit is contained in:
Dmitry Stogov 2014-11-24 20:33:27 +03:00
parent 899c24a8c1
commit 42d33a9fc6
3 changed files with 61 additions and 105 deletions

View file

@ -692,7 +692,7 @@ static void zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t ar
static zend_always_inline void zend_assign_to_object(zval *retval, zval *object, uint32_t object_op_type, zval *property_name, int value_type, const znode_op *value_op, const zend_execute_data *execute_data, int opcode, void **cache_slot TSRMLS_DC)
{
zend_free_op free_value;
zval *value = get_zval_ptr(value_type, value_op, execute_data, &free_value, BP_VAR_R);
zval *value = get_zval_ptr_deref(value_type, value_op, execute_data, &free_value, BP_VAR_R);
zval tmp;
if (object_op_type != IS_UNUSED) {
@ -830,65 +830,6 @@ static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *valu
}
}
static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value, zend_uchar value_type TSRMLS_DC)
{
do {
if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
zend_refcounted *garbage;
if (Z_ISREF_P(variable_ptr)) {
variable_ptr = Z_REFVAL_P(variable_ptr);
if (EXPECTED(!Z_REFCOUNTED_P(variable_ptr))) {
break;
}
}
if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr, value TSRMLS_CC);
return variable_ptr;
}
if ((value_type & (IS_VAR|IS_CV)) && variable_ptr == value) {
return variable_ptr;
}
garbage = Z_COUNTED_P(variable_ptr);
if (--GC_REFCOUNT(garbage) == 0) {
ZVAL_COPY_VALUE(variable_ptr, value);
if (value_type == IS_CONST) {
/* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) {
zval_copy_ctor_func(variable_ptr);
}
} else if (value_type != IS_TMP_VAR) {
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(variable_ptr))) {
Z_ADDREF_P(variable_ptr);
}
}
_zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC);
return variable_ptr;
} else { /* we need to split */
/* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */
if ((Z_COLLECTABLE_P(variable_ptr)) &&
UNEXPECTED(!GC_INFO(garbage))) {
gc_possible_root(garbage TSRMLS_CC);
}
}
}
} while (0);
ZVAL_COPY_VALUE(variable_ptr, value);
if (value_type == IS_CONST) {
/* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) {
zval_copy_ctor_func(variable_ptr);
}
} else if (value_type != IS_TMP_VAR) {
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(variable_ptr))) {
Z_ADDREF_P(variable_ptr);
}
}
return variable_ptr;
}
/* Utility Functions for Extensions */
static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
{

View file

@ -129,6 +129,65 @@ again:
return result;
}
static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value, zend_uchar value_type TSRMLS_DC)
{
do {
if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
zend_refcounted *garbage;
if (Z_ISREF_P(variable_ptr)) {
variable_ptr = Z_REFVAL_P(variable_ptr);
if (EXPECTED(!Z_REFCOUNTED_P(variable_ptr))) {
break;
}
}
if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr, value TSRMLS_CC);
return variable_ptr;
}
if ((value_type & (IS_VAR|IS_CV)) && variable_ptr == value) {
return variable_ptr;
}
garbage = Z_COUNTED_P(variable_ptr);
if (--GC_REFCOUNT(garbage) == 0) {
ZVAL_COPY_VALUE(variable_ptr, value);
if (value_type == IS_CONST) {
/* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) {
zval_copy_ctor_func(variable_ptr);
}
} else if (value_type != IS_TMP_VAR) {
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(variable_ptr))) {
Z_ADDREF_P(variable_ptr);
}
}
_zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC);
return variable_ptr;
} else { /* we need to split */
/* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */
if ((Z_COLLECTABLE_P(variable_ptr)) &&
UNEXPECTED(!GC_INFO(garbage))) {
gc_possible_root(garbage TSRMLS_CC);
}
}
}
} while (0);
ZVAL_COPY_VALUE(variable_ptr, value);
if (value_type == IS_CONST) {
/* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) {
zval_copy_ctor_func(variable_ptr);
}
} else if (value_type != IS_TMP_VAR) {
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(variable_ptr))) {
Z_ADDREF_P(variable_ptr);
}
}
return variable_ptr;
}
ZEND_API int zval_update_constant(zval *pp, zend_bool inline_change TSRMLS_DC);
ZEND_API int zval_update_constant_inline_change(zval *pp, zend_class_entry *scope TSRMLS_DC);
ZEND_API int zval_update_constant_no_inline_change(zval *pp, zend_class_entry *scope TSRMLS_DC);

View file

@ -545,51 +545,7 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, v
} else if (EXPECTED(zobj->properties != NULL)) {
if ((variable_ptr = zend_hash_find(zobj->properties, Z_STR_P(member))) != NULL) {
found:
/* if we already have this value there, we don't actually need to do anything */
if (EXPECTED(variable_ptr != value)) {
/* if we are assigning reference, we shouldn't move it, but instead assign variable
to the same pointer */
if (Z_ISREF_P(variable_ptr)) {
zval garbage;
ZVAL_COPY_VALUE(&garbage, Z_REFVAL_P(variable_ptr)); /* old value should be destroyed */
/* To check: can't *variable_ptr be some system variable like error_zval here? */
if (UNEXPECTED(Z_REFCOUNTED_P(value))) {
if (EXPECTED(!Z_ISREF_P(value))) {
Z_ADDREF_P(value);
} else {
if (Z_REFCOUNT_P(value) == 1) {
ZVAL_UNREF(value);
} else {
value = Z_REFVAL_P(value);
}
if (Z_REFCOUNTED_P(value)) {
if (UNEXPECTED(Z_REFVAL_P(variable_ptr) == value)) {
goto exit;
}
Z_ADDREF_P(value);
}
}
}
ZVAL_COPY_VALUE(Z_REFVAL_P(variable_ptr), value);
zval_ptr_dtor(&garbage);
} else {
zval garbage;
ZVAL_COPY_VALUE(&garbage, variable_ptr);
/* if we assign referenced variable, we should separate it */
ZVAL_COPY_VALUE(variable_ptr, value);
if (Z_REFCOUNTED_P(variable_ptr)) {
Z_ADDREF_P(variable_ptr);
if (Z_ISREF_P(variable_ptr)) {
SEPARATE_ZVAL(variable_ptr);
}
}
zval_ptr_dtor(&garbage);
}
}
zend_assign_to_variable(variable_ptr, value, (IS_VAR|IS_TMP_VAR) TSRMLS_CC);
goto exit;
}
}