summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/zend_execute.c40
-rw-r--r--Zend/zend_execute.h73
2 files changed, 65 insertions, 48 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 10dd64a15d..bf4a8e224a 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -3026,6 +3026,46 @@ ZEND_API zend_bool ZEND_FASTCALL zend_verify_ref_assignable_zval(zend_reference
return i_zend_verify_ref_assignable_zval(ref, zv, strict);
}
+ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *value, zend_uchar value_type, zend_bool strict, zend_refcounted *ref)
+{
+ zend_bool need_copy = ZEND_CONST_COND(value_type & (IS_CONST|IS_CV), 1) ||
+ ((value_type & IS_VAR) && UNEXPECTED(ref) && GC_REFCOUNT(ref) > 1);
+ zend_bool ret;
+ zval tmp;
+
+ if (need_copy) {
+ ZVAL_COPY(&tmp, value);
+ value = &tmp;
+ }
+ ret = zend_verify_ref_assignable_zval(Z_REF_P(variable_ptr), value, strict);
+ if (need_copy) {
+ Z_TRY_DELREF_P(value);
+ }
+ if (!ret) {
+ zval_ptr_dtor(value);
+ return Z_REFVAL_P(variable_ptr);
+ }
+
+ variable_ptr = Z_REFVAL_P(variable_ptr);
+ if (EXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
+ zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
+
+ zend_copy_to_variable(variable_ptr, value, value_type, ref);
+ if (GC_DELREF(garbage) == 0) {
+ rc_dtor_func(garbage);
+ } else { /* we need to split */
+ /* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */
+ if (UNEXPECTED(GC_MAY_LEAK(garbage))) {
+ gc_possible_root(garbage);
+ }
+ }
+ return variable_ptr;
+ }
+
+ zend_copy_to_variable(variable_ptr, value, value_type, ref);
+ return variable_ptr;
+}
+
ZEND_API zend_bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref(zend_property_info *prop_info, zval *orig_val, zend_bool strict) {
zval *val = orig_val;
if (Z_ISREF_P(val) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(val))) {
diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h
index e34c56def2..053d22afd0 100644
--- a/Zend/zend_execute.h
+++ b/Zend/zend_execute.h
@@ -78,10 +78,31 @@ ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(zend_property_info *prop1
ZEND_API void ZEND_FASTCALL zend_ref_add_type_source(zend_property_info_source_list *source_list, zend_property_info *prop);
ZEND_API void ZEND_FASTCALL zend_ref_del_type_source(zend_property_info_source_list *source_list, zend_property_info *prop);
+ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *value, zend_uchar value_type, zend_bool strict, zend_refcounted *ref);
+
+static zend_always_inline void zend_copy_to_variable(zval *variable_ptr, zval *value, zend_uchar value_type, zend_refcounted *ref)
+{
+ ZVAL_COPY_VALUE(variable_ptr, value);
+ if (ZEND_CONST_COND(value_type == IS_CONST, 0)) {
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(variable_ptr))) {
+ Z_ADDREF_P(variable_ptr);
+ }
+ } else if (value_type & (IS_CONST|IS_CV)) {
+ if (Z_OPT_REFCOUNTED_P(variable_ptr)) {
+ Z_ADDREF_P(variable_ptr);
+ }
+ } else if (ZEND_CONST_COND(value_type == IS_VAR, 1) && UNEXPECTED(ref)) {
+ if (UNEXPECTED(GC_DELREF(ref) == 0)) {
+ efree_size(ref, sizeof(zend_reference));
+ } else if (Z_OPT_REFCOUNTED_P(variable_ptr)) {
+ Z_ADDREF_P(variable_ptr);
+ }
+ }
+}
+
static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value, zend_uchar value_type, zend_bool strict)
{
zend_refcounted *ref = NULL;
- zval tmp;
if (ZEND_CONST_COND(value_type & (IS_VAR|IS_CV), 1) && Z_ISREF_P(value)) {
ref = Z_COUNTED_P(value);
@@ -94,21 +115,7 @@ static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval
if (Z_ISREF_P(variable_ptr)) {
if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(variable_ptr)))) {
- zend_bool need_copy = ZEND_CONST_COND(value_type & (IS_CONST|IS_CV), 1) ||
- ((value_type & IS_VAR) && UNEXPECTED(ref) && GC_REFCOUNT(ref) > 1);
- zend_bool ret;
- if (need_copy) {
- ZVAL_COPY(&tmp, value);
- value = &tmp;
- }
- ret = zend_verify_ref_assignable_zval(Z_REF_P(variable_ptr), value, strict);
- if (need_copy) {
- Z_TRY_DELREF_P(value);
- }
- if (!ret) {
- zval_ptr_dtor(value);
- return Z_REFVAL_P(variable_ptr);
- }
+ return zend_assign_to_typed_ref(variable_ptr, value, value_type, strict, ref);
}
variable_ptr = Z_REFVAL_P(variable_ptr);
@@ -117,22 +124,7 @@ static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval
}
}
garbage = Z_COUNTED_P(variable_ptr);
- ZVAL_COPY_VALUE(variable_ptr, value);
- if (ZEND_CONST_COND(value_type == IS_CONST, 0)) {
- if (UNEXPECTED(Z_OPT_REFCOUNTED_P(variable_ptr))) {
- Z_ADDREF_P(variable_ptr);
- }
- } else if (value_type & (IS_CONST|IS_CV)) {
- if (Z_OPT_REFCOUNTED_P(variable_ptr)) {
- Z_ADDREF_P(variable_ptr);
- }
- } else if (ZEND_CONST_COND(value_type == IS_VAR, 1) && UNEXPECTED(ref)) {
- if (UNEXPECTED(GC_DELREF(ref) == 0)) {
- efree_size(ref, sizeof(zend_reference));
- } else if (Z_OPT_REFCOUNTED_P(variable_ptr)) {
- Z_ADDREF_P(variable_ptr);
- }
- }
+ zend_copy_to_variable(variable_ptr, value, value_type, ref);
if (GC_DELREF(garbage) == 0) {
rc_dtor_func(garbage);
} else { /* we need to split */
@@ -145,22 +137,7 @@ static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval
}
} while (0);
- ZVAL_COPY_VALUE(variable_ptr, value);
- if (ZEND_CONST_COND(value_type == IS_CONST, 0)) {
- if (UNEXPECTED(Z_OPT_REFCOUNTED_P(variable_ptr))) {
- Z_ADDREF_P(variable_ptr);
- }
- } else if (value_type & (IS_CONST|IS_CV)) {
- if (Z_OPT_REFCOUNTED_P(variable_ptr)) {
- Z_ADDREF_P(variable_ptr);
- }
- } else if (ZEND_CONST_COND(value_type == IS_VAR, 1) && UNEXPECTED(ref)) {
- if (UNEXPECTED(GC_DELREF(ref) == 0)) {
- efree_size(ref, sizeof(zend_reference));
- } else if (Z_OPT_REFCOUNTED_P(variable_ptr)) {
- Z_ADDREF_P(variable_ptr);
- }
- }
+ zend_copy_to_variable(variable_ptr, value, value_type, ref);
return variable_ptr;
}