mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Improved reference counting
This commit is contained in:
parent
f26592846f
commit
adcf0c6052
6 changed files with 648 additions and 322 deletions
|
@ -971,7 +971,7 @@ static inline int zend_verify_missing_return_type(zend_function *zf)
|
|||
static zend_always_inline void zend_assign_to_object(zval *retval, zval *object, uint32_t object_op_type, zval *property_name, uint32_t property_op_type, int value_type, znode_op value_op, const zend_execute_data *execute_data, void **cache_slot)
|
||||
{
|
||||
zend_free_op free_value;
|
||||
zval *value = get_zval_ptr_deref(value_type, value_op, execute_data, &free_value, BP_VAR_R);
|
||||
zval *value = get_zval_ptr(value_type, value_op, execute_data, &free_value, BP_VAR_R);
|
||||
zval tmp;
|
||||
|
||||
if (object_op_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
|
||||
|
@ -1033,9 +1033,6 @@ fast_assign:
|
|||
if (retval && !EG(exception)) {
|
||||
ZVAL_COPY(retval, value);
|
||||
}
|
||||
if (value_type == IS_VAR) {
|
||||
FREE_OP(free_value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
@ -1057,10 +1054,12 @@ fast_assign:
|
|||
zval_copy_ctor_func(&tmp);
|
||||
value = &tmp;
|
||||
}
|
||||
} else if (value_type != IS_TMP_VAR &&
|
||||
Z_REFCOUNTED_P(value)) {
|
||||
} else if (value_type != IS_TMP_VAR) {
|
||||
ZVAL_DEREF(value);
|
||||
if (Z_REFCOUNTED_P(value)) {
|
||||
Z_ADDREF_P(value);
|
||||
}
|
||||
}
|
||||
zend_hash_add_new(zobj->properties, Z_STR_P(property_name), value);
|
||||
if (retval && !EG(exception)) {
|
||||
ZVAL_COPY(retval, value);
|
||||
|
@ -1089,10 +1088,12 @@ fast_assign:
|
|||
zval_copy_ctor_func(&tmp);
|
||||
value = &tmp;
|
||||
}
|
||||
} else if (value_type != IS_TMP_VAR &&
|
||||
Z_REFCOUNTED_P(value)) {
|
||||
} else if (value_type != IS_TMP_VAR) {
|
||||
ZVAL_DEREF(value);
|
||||
if (Z_REFCOUNTED_P(value)) {
|
||||
Z_ADDREF_P(value);
|
||||
}
|
||||
}
|
||||
|
||||
Z_OBJ_HT_P(object)->write_property(object, property_name, value, cache_slot);
|
||||
|
||||
|
|
|
@ -55,6 +55,13 @@ ZEND_API void zend_verify_internal_return_error(const zend_function *zf, const c
|
|||
|
||||
static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value, zend_uchar value_type)
|
||||
{
|
||||
zend_refcounted *ref = NULL;
|
||||
|
||||
if ((value_type & (IS_VAR|IS_CV)) && Z_ISREF_P(value)) {
|
||||
ref = Z_COUNTED_P(value);
|
||||
value = Z_REFVAL_P(value);
|
||||
}
|
||||
|
||||
do {
|
||||
if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
|
||||
zend_refcounted *garbage;
|
||||
|
@ -81,12 +88,18 @@ static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval
|
|||
if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) {
|
||||
zval_copy_ctor_func(variable_ptr);
|
||||
}
|
||||
} else if (value_type != IS_TMP_VAR) {
|
||||
} else if (value_type == IS_CV) {
|
||||
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(variable_ptr))) {
|
||||
Z_ADDREF_P(variable_ptr);
|
||||
}
|
||||
} else if (/* value_type == IS_VAR && */ UNEXPECTED(ref)) {
|
||||
if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) {
|
||||
efree_size(ref, sizeof(zend_reference));
|
||||
} else if (Z_OPT_REFCOUNTED_P(variable_ptr)) {
|
||||
Z_ADDREF_P(variable_ptr);
|
||||
}
|
||||
_zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC);
|
||||
}
|
||||
zval_dtor_func_for_ptr(garbage);
|
||||
return variable_ptr;
|
||||
} else { /* we need to split */
|
||||
/* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */
|
||||
|
@ -104,10 +117,16 @@ static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval
|
|||
if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) {
|
||||
zval_copy_ctor_func(variable_ptr);
|
||||
}
|
||||
} else if (value_type != IS_TMP_VAR) {
|
||||
} else if (value_type == IS_CV) {
|
||||
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(variable_ptr))) {
|
||||
Z_ADDREF_P(variable_ptr);
|
||||
}
|
||||
} else if (/* value_type == IS_VAR && */ UNEXPECTED(ref)) {
|
||||
if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) {
|
||||
efree_size(ref, sizeof(zend_reference));
|
||||
} else if (Z_OPT_REFCOUNTED_P(variable_ptr)) {
|
||||
Z_ADDREF_P(variable_ptr);
|
||||
}
|
||||
}
|
||||
return variable_ptr;
|
||||
}
|
||||
|
|
|
@ -625,7 +625,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:
|
||||
zend_assign_to_variable(variable_ptr, value, (IS_VAR|IS_TMP_VAR));
|
||||
zend_assign_to_variable(variable_ptr, value, IS_CV);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ ZEND_API void ZEND_FASTCALL _zval_dtor_func(zend_refcounted *p ZEND_FILE_LINE_DC
|
|||
ZEND_API void ZEND_FASTCALL _zval_dtor_func_for_ptr(zend_refcounted *p ZEND_FILE_LINE_DC);
|
||||
ZEND_API void ZEND_FASTCALL _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC);
|
||||
|
||||
#define zval_dtor_func(p) _zval_dtor_func(zv ZEND_FILE_LINE_CC)
|
||||
#define zval_dtor_func_for_ptr(p) _zval_dtor_func_for_ptr(zv ZEND_FILE_LINE_CC)
|
||||
#define zval_dtor_func(zv) _zval_dtor_func(zv ZEND_FILE_LINE_CC)
|
||||
#define zval_dtor_func_for_ptr(zv) _zval_dtor_func_for_ptr(zv ZEND_FILE_LINE_CC)
|
||||
#define zval_copy_ctor_func(zv) _zval_copy_ctor_func(zv ZEND_FILE_LINE_CC)
|
||||
|
||||
static zend_always_inline void _zval_dtor(zval *zvalue ZEND_FILE_LINE_DC)
|
||||
|
|
|
@ -2184,7 +2184,7 @@ ZEND_VM_C_LABEL(try_assign_dim_array):
|
|||
variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, OP2_TYPE, BP_VAR_W);
|
||||
FREE_OP2();
|
||||
}
|
||||
value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
|
||||
value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
|
||||
if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
|
||||
FREE_OP(free_op_data1);
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
|
@ -2192,9 +2192,6 @@ ZEND_VM_C_LABEL(try_assign_dim_array):
|
|||
}
|
||||
} else {
|
||||
value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type);
|
||||
if ((opline+1)->op1_type == IS_VAR) {
|
||||
FREE_OP(free_op_data1);
|
||||
}
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
}
|
||||
|
@ -2263,13 +2260,11 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV)
|
|||
zval *variable_ptr;
|
||||
|
||||
SAVE_OPLINE();
|
||||
value = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R);
|
||||
value = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
|
||||
|
||||
if (OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) {
|
||||
if (OP2_TYPE == IS_TMP_VAR) {
|
||||
FREE_OP2();
|
||||
}
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
}
|
||||
|
@ -2279,10 +2274,8 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV)
|
|||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
}
|
||||
FREE_OP1_VAR_PTR();
|
||||
}
|
||||
|
||||
/* zend_assign_to_variable() always takes care of op2, never free it! */
|
||||
FREE_OP2_IF_VAR();
|
||||
}
|
||||
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
|
@ -3788,13 +3781,22 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY)
|
|||
zval_copy_ctor_func(EX(return_value));
|
||||
}
|
||||
}
|
||||
} else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(retval_ptr)) {
|
||||
ZVAL_COPY(EX(return_value), Z_REFVAL_P(retval_ptr));
|
||||
FREE_OP1_IF_VAR();
|
||||
} else if (OP1_TYPE == IS_CV) {
|
||||
ZVAL_DEREF(retval_ptr);
|
||||
ZVAL_COPY(EX(return_value), retval_ptr);
|
||||
} else /* if (OP1_TYPE == IS_VAR) */ {
|
||||
if (UNEXPECTED(Z_ISREF_P(retval_ptr))) {
|
||||
zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
|
||||
|
||||
retval_ptr = Z_REFVAL_P(retval_ptr);
|
||||
ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
|
||||
if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) {
|
||||
efree_size(ref, sizeof(zend_reference));
|
||||
} else if (Z_OPT_REFCOUNTED_P(retval_ptr)) {
|
||||
Z_ADDREF_P(retval_ptr);
|
||||
}
|
||||
} else {
|
||||
ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
if (Z_OPT_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3884,13 +3886,22 @@ ZEND_VM_HANDLER(161, ZEND_GENERATOR_RETURN, CONST|TMP|VAR|CV, ANY)
|
|||
zval_copy_ctor_func(&generator->retval);
|
||||
}
|
||||
}
|
||||
} else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(retval)) {
|
||||
ZVAL_COPY(&generator->retval, Z_REFVAL_P(retval));
|
||||
FREE_OP1_IF_VAR();
|
||||
} else if (OP1_TYPE == IS_CV) {
|
||||
ZVAL_DEREF(retval);
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
} else /* if (OP1_TYPE == IS_VAR) */ {
|
||||
if (UNEXPECTED(Z_ISREF_P(retval))) {
|
||||
zend_refcounted *ref = Z_COUNTED_P(retval);
|
||||
|
||||
retval = Z_REFVAL_P(retval);
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) {
|
||||
efree_size(ref, sizeof(zend_reference));
|
||||
} else if (Z_OPT_REFCOUNTED_P(retval)) {
|
||||
Z_ADDREF_P(retval);
|
||||
}
|
||||
} else {
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
if (Z_OPT_REFCOUNTED_P(retval)) Z_ADDREF_P(retval);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4037,19 +4048,31 @@ ZEND_VM_HANDLER(117, ZEND_SEND_VAR, VAR|CV, ANY)
|
|||
USE_OPLINE
|
||||
zval *varptr, *arg;
|
||||
zend_free_op free_op1;
|
||||
zend_refcounted *ref;
|
||||
|
||||
SAVE_OPLINE();
|
||||
varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||
arg = ZEND_CALL_VAR(EX(call), opline->result.var);
|
||||
if (Z_ISREF_P(varptr)) {
|
||||
ZVAL_COPY(arg, Z_REFVAL_P(varptr));
|
||||
FREE_OP1();
|
||||
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
ZVAL_DEREF(varptr);
|
||||
ZVAL_COPY(arg, varptr);
|
||||
} else /* if (OP1_TYPE == IS_VAR) */ {
|
||||
if (UNEXPECTED(Z_ISREF_P(varptr))) {
|
||||
zend_refcounted *ref = Z_COUNTED_P(varptr);
|
||||
|
||||
varptr = Z_REFVAL_P(varptr);
|
||||
ZVAL_COPY_VALUE(arg, varptr);
|
||||
if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) {
|
||||
efree_size(ref, sizeof(zend_reference));
|
||||
} else if (Z_OPT_REFCOUNTED_P(arg)) {
|
||||
Z_ADDREF_P(arg);
|
||||
}
|
||||
} else {
|
||||
ZVAL_COPY_VALUE(arg, varptr);
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
|
@ -4140,15 +4163,26 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR_EX, VAR|CV, ANY)
|
|||
SAVE_OPLINE();
|
||||
varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||
arg = ZEND_CALL_VAR(EX(call), opline->result.var);
|
||||
if (Z_ISREF_P(varptr)) {
|
||||
ZVAL_COPY(arg, Z_REFVAL_P(varptr));
|
||||
FREE_OP1();
|
||||
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
ZVAL_DEREF(varptr);
|
||||
ZVAL_COPY(arg, varptr);
|
||||
} else /* if (OP1_TYPE == IS_VAR) */ {
|
||||
if (UNEXPECTED(Z_ISREF_P(varptr))) {
|
||||
zend_refcounted *ref = Z_COUNTED_P(varptr);
|
||||
|
||||
varptr = Z_REFVAL_P(varptr);
|
||||
ZVAL_COPY_VALUE(arg, varptr);
|
||||
if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) {
|
||||
efree_size(ref, sizeof(zend_reference));
|
||||
} else if (Z_OPT_REFCOUNTED_P(arg)) {
|
||||
Z_ADDREF_P(arg);
|
||||
}
|
||||
} else {
|
||||
ZVAL_COPY_VALUE(arg, varptr);
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
|
@ -5008,13 +5042,25 @@ ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUSE
|
|||
ZVAL_DUP(&new_expr, expr_ptr);
|
||||
expr_ptr = &new_expr;
|
||||
}
|
||||
} else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(expr_ptr)) {
|
||||
expr_ptr = Z_REFVAL_P(expr_ptr);
|
||||
if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr);
|
||||
FREE_OP1_IF_VAR();
|
||||
} else if (OP1_TYPE == IS_CV && Z_REFCOUNTED_P(expr_ptr)) {
|
||||
} else if (OP1_TYPE == IS_CV) {
|
||||
ZVAL_DEREF(expr_ptr);
|
||||
if (Z_REFCOUNTED_P(expr_ptr)) {
|
||||
Z_ADDREF_P(expr_ptr);
|
||||
}
|
||||
} else /* if (OP1_TYPE == IS_VAR) */ {
|
||||
if (UNEXPECTED(Z_ISREF_P(expr_ptr))) {
|
||||
zend_refcounted *ref = Z_COUNTED_P(expr_ptr);
|
||||
|
||||
expr_ptr = Z_REFVAL_P(expr_ptr);
|
||||
if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) {
|
||||
ZVAL_COPY_VALUE(&new_expr, expr_ptr);
|
||||
expr_ptr = &new_expr;
|
||||
efree_size(ref, sizeof(zend_reference));
|
||||
} else if (Z_OPT_REFCOUNTED_P(expr_ptr)) {
|
||||
Z_ADDREF_P(expr_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (OP2_TYPE != IS_UNUSED) {
|
||||
|
@ -5349,7 +5395,7 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
|
|||
|
||||
if (!--GC_REFCOUNT(garbage)) {
|
||||
ZVAL_UNDEF(var);
|
||||
_zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC);
|
||||
zval_dtor_func_for_ptr(garbage);
|
||||
} else {
|
||||
GC_ZVAL_CHECK_POSSIBLE_ROOT(var);
|
||||
ZVAL_UNDEF(var);
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue