diff options
author | Dmitry Stogov <dmitry@zend.com> | 2016-10-21 17:47:30 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2016-10-21 17:47:30 +0300 |
commit | d6c332eb513371bc7fc6b8b53016b50c73aad158 (patch) | |
tree | c995e024987ff7798fc8ebfb684a08e05b6f3323 | |
parent | 04bba0c078ccbe65672c8ec1476eb9af4b6b432c (diff) | |
download | php-git-d6c332eb513371bc7fc6b8b53016b50c73aad158.tar.gz |
Turn IS_TYPE_COLLECTABLE zval flag into GC_COLLECTABLE zend_refcounted flag.
This simplifies checks and allows reset this flag for "acyclic" arrays and objects.
-rw-r--r-- | Zend/zend_execute.c | 8 | ||||
-rw-r--r-- | Zend/zend_execute.h | 9 | ||||
-rw-r--r-- | Zend/zend_gc.h | 23 | ||||
-rw-r--r-- | Zend/zend_hash.c | 4 | ||||
-rw-r--r-- | Zend/zend_objects.c | 2 | ||||
-rw-r--r-- | Zend/zend_objects_API.h | 2 | ||||
-rw-r--r-- | Zend/zend_types.h | 31 | ||||
-rw-r--r-- | Zend/zend_variables.h | 7 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 18 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 40 |
10 files changed, 65 insertions, 79 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 8e3d5fd187..1bc67fb3ca 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -584,7 +584,7 @@ static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *v zval_dtor_func(garbage); return; } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr); + gc_check_possible_root(garbage); } } ZVAL_REF(variable_ptr, ref); @@ -2063,12 +2063,12 @@ static zend_always_inline void i_free_compiled_variables(zend_execute_data *exec zval *end = cv + EX(func)->op_array.last_var; while (EXPECTED(cv != end)) { if (Z_REFCOUNTED_P(cv)) { - if (!Z_DELREF_P(cv)) { - zend_refcounted *r = Z_COUNTED_P(cv); + zend_refcounted *r = Z_COUNTED_P(cv); + if (!--GC_REFCOUNT(r)) { ZVAL_NULL(cv); zval_dtor_func(r); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(cv); + gc_check_possible_root(r); } } cv++; diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 82c6a4a415..4d68fea800 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -101,8 +101,7 @@ static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval 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))) { + if (UNEXPECTED(GC_MAY_LEAK(garbage))) { gc_possible_root(garbage); } } @@ -216,12 +215,12 @@ static zend_always_inline void zend_vm_stack_free_extra_args_ex(uint32_t call_in do { p--; if (Z_REFCOUNTED_P(p)) { - if (!Z_DELREF_P(p)) { - zend_refcounted *r = Z_COUNTED_P(p); + zend_refcounted *r = Z_COUNTED_P(p); + if (!--GC_REFCOUNT(r)) { ZVAL_NULL(p); zval_dtor_func(r); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(p); + gc_check_possible_root(r); } } } while (p != end); diff --git a/Zend/zend_gc.h b/Zend/zend_gc.h index eb8e500b03..be6b8c44fd 100644 --- a/Zend/zend_gc.h +++ b/Zend/zend_gc.h @@ -119,9 +119,6 @@ ZEND_API void gc_reset(void); ZEND_API int zend_gc_collect_cycles(void); END_EXTERN_C() -#define GC_ZVAL_CHECK_POSSIBLE_ROOT(z) \ - gc_check_possible_root((z)) - #define GC_REMOVE_FROM_BUFFER(p) do { \ zend_refcounted *_p = (zend_refcounted*)(p); \ if (GC_ADDRESS(GC_INFO(_p))) { \ @@ -129,11 +126,23 @@ END_EXTERN_C() } \ } while (0) -static zend_always_inline void gc_check_possible_root(zval *z) +#define GC_MAY_LEAK(ref) \ + ((GC_TYPE_INFO(ref) & \ + (GC_INFO_MASK | (GC_COLLECTABLE << GC_FLAGS_SHIFT))) == \ + (GC_COLLECTABLE << GC_FLAGS_SHIFT)) + +static zend_always_inline void gc_check_possible_root(zend_refcounted *ref) { - ZVAL_DEREF(z); - if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { - gc_possible_root(Z_COUNTED_P(z)); + if (GC_TYPE(ref) == IS_REFERENCE) { + zval *zv = &((zend_reference*)ref)->val; + + if (!Z_REFCOUNTED_P(zv)) { + return; + } + ref = Z_COUNTED_P(zv); + } + if (UNEXPECTED(GC_MAY_LEAK(ref))) { + gc_possible_root(ref); } } diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index e83fc41cf4..c3cae2a831 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -171,7 +171,7 @@ static const uint32_t uninitialized_bucket[-HT_MIN_MASK] = ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) { GC_REFCOUNT(ht) = 1; - GC_TYPE_INFO(ht) = IS_ARRAY; + GC_TYPE_INFO(ht) = IS_ARRAY | (persistent ? 0 : (GC_COLLECTABLE << GC_FLAGS_SHIFT)); ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION | HASH_FLAG_STATIC_KEYS; ht->nTableSize = zend_hash_check_size(nSize); ht->nTableMask = HT_MIN_MASK; @@ -1760,7 +1760,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source) ALLOC_HASHTABLE(target); GC_REFCOUNT(target) = 1; - GC_TYPE_INFO(target) = IS_ARRAY; + GC_TYPE_INFO(target) = IS_ARRAY | (GC_COLLECTABLE << GC_FLAGS_SHIFT); target->nTableSize = source->nTableSize; target->pDestructor = source->pDestructor; diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 1e358996ed..07b586b6f8 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -32,7 +32,7 @@ ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce) zval *p, *end; GC_REFCOUNT(object) = 1; - GC_TYPE_INFO(object) = IS_OBJECT; + GC_TYPE_INFO(object) = IS_OBJECT | (GC_COLLECTABLE << GC_FLAGS_SHIFT); object->ce = ce; object->properties = NULL; zend_objects_store_put(object); diff --git a/Zend/zend_objects_API.h b/Zend/zend_objects_API.h index dbdb02f984..7dfad70fbc 100644 --- a/Zend/zend_objects_API.h +++ b/Zend/zend_objects_API.h @@ -76,7 +76,7 @@ static zend_always_inline void zend_object_release(zend_object *obj) { if (--GC_REFCOUNT(obj) == 0) { zend_objects_store_del(obj); - } else if (UNEXPECTED(!GC_INFO(obj))) { + } else if (UNEXPECTED(GC_MAY_LEAK((zend_refcounted*)obj))) { gc_possible_root((zend_refcounted*)obj); } } diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 2a108877bf..9d4f6a7d4c 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -390,24 +390,33 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) { #define Z_GC_TYPE_INFO(zval) GC_TYPE_INFO(Z_COUNTED(zval)) #define Z_GC_TYPE_INFO_P(zval_p) Z_GC_TYPE_INFO(*(zval_p)) +#define GC_FLAGS_SHIFT 8 +#define GC_INFO_SHIFT 16 +#define GC_INFO_MASK 0xffff0000 + +/* zval.value->gc.u.v.flags */ +#define GC_COLLECTABLE (1<<7) + +#define GC_ARRAY (IS_ARRAY | (GC_COLLECTABLE << GC_FLAGS_SHIFT)) +#define GC_OBJECT (IS_OBJECT | (GC_COLLECTABLE << GC_FLAGS_SHIFT)) + /* zval.u1.v.type_flags */ #define IS_TYPE_CONSTANT (1<<0) #define IS_TYPE_IMMUTABLE (1<<1) #define IS_TYPE_REFCOUNTED (1<<2) -#define IS_TYPE_COLLECTABLE (1<<3) #define IS_TYPE_COPYABLE (1<<4) /* extended types */ #define IS_INTERNED_STRING_EX IS_STRING -#define IS_STRING_EX (IS_STRING | (( IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT)) -#define IS_ARRAY_EX (IS_ARRAY | (( IS_TYPE_REFCOUNTED | IS_TYPE_COLLECTABLE | IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT)) -#define IS_OBJECT_EX (IS_OBJECT | (( IS_TYPE_REFCOUNTED | IS_TYPE_COLLECTABLE ) << Z_TYPE_FLAGS_SHIFT)) -#define IS_RESOURCE_EX (IS_RESOURCE | (( IS_TYPE_REFCOUNTED ) << Z_TYPE_FLAGS_SHIFT)) -#define IS_REFERENCE_EX (IS_REFERENCE | (( IS_TYPE_REFCOUNTED ) << Z_TYPE_FLAGS_SHIFT)) +#define IS_STRING_EX (IS_STRING | (( IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT)) +#define IS_ARRAY_EX (IS_ARRAY | (( IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT)) +#define IS_OBJECT_EX (IS_OBJECT | (( IS_TYPE_REFCOUNTED ) << Z_TYPE_FLAGS_SHIFT)) +#define IS_RESOURCE_EX (IS_RESOURCE | (( IS_TYPE_REFCOUNTED ) << Z_TYPE_FLAGS_SHIFT)) +#define IS_REFERENCE_EX (IS_REFERENCE | (( IS_TYPE_REFCOUNTED ) << Z_TYPE_FLAGS_SHIFT)) -#define IS_CONSTANT_EX (IS_CONSTANT | ((IS_TYPE_CONSTANT | IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT)) -#define IS_CONSTANT_AST_EX (IS_CONSTANT_AST | ((IS_TYPE_CONSTANT | IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT)) +#define IS_CONSTANT_EX (IS_CONSTANT | ((IS_TYPE_CONSTANT | IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT)) +#define IS_CONSTANT_AST_EX (IS_CONSTANT_AST | ((IS_TYPE_CONSTANT | IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT)) /* zval.u1.v.const_flags */ #define IS_CONSTANT_UNQUALIFIED 0x010 @@ -463,9 +472,6 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) { #define Z_REFCOUNTED(zval) ((Z_TYPE_FLAGS(zval) & IS_TYPE_REFCOUNTED) != 0) #define Z_REFCOUNTED_P(zval_p) Z_REFCOUNTED(*(zval_p)) -#define Z_COLLECTABLE(zval) ((Z_TYPE_FLAGS(zval) & IS_TYPE_COLLECTABLE) != 0) -#define Z_COLLECTABLE_P(zval_p) Z_COLLECTABLE(*(zval_p)) - #define Z_COPYABLE(zval) ((Z_TYPE_FLAGS(zval) & IS_TYPE_COPYABLE) != 0) #define Z_COPYABLE_P(zval_p) Z_COPYABLE(*(zval_p)) @@ -482,9 +488,6 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) { #define Z_OPT_REFCOUNTED(zval) ((Z_TYPE_INFO(zval) & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) != 0) #define Z_OPT_REFCOUNTED_P(zval_p) Z_OPT_REFCOUNTED(*(zval_p)) -#define Z_OPT_COLLECTABLE(zval) ((Z_TYPE_INFO(zval) & (IS_TYPE_COLLECTABLE << Z_TYPE_FLAGS_SHIFT)) != 0) -#define Z_OPT_COLLECTABLE_P(zval_p) Z_OPT_COLLECTABLE(*(zval_p)) - #define Z_OPT_COPYABLE(zval) ((Z_TYPE_INFO(zval) & (IS_TYPE_COPYABLE << Z_TYPE_FLAGS_SHIFT)) != 0) #define Z_OPT_COPYABLE_P(zval_p) Z_OPT_COPYABLE(*(zval_p)) diff --git a/Zend/zend_variables.h b/Zend/zend_variables.h index 0afe68760d..b0054eedd3 100644 --- a/Zend/zend_variables.h +++ b/Zend/zend_variables.h @@ -44,10 +44,11 @@ static zend_always_inline void _zval_ptr_dtor_nogc(zval *zval_ptr ZEND_FILE_LINE static zend_always_inline void i_zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) { if (Z_REFCOUNTED_P(zval_ptr)) { - if (!Z_DELREF_P(zval_ptr)) { - _zval_dtor_func(Z_COUNTED_P(zval_ptr) ZEND_FILE_LINE_RELAY_CC); + zend_refcounted *ref = Z_COUNTED_P(zval_ptr); + if (!--GC_REFCOUNT(ref)) { + _zval_dtor_func(ref ZEND_FILE_LINE_RELAY_CC); } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(zval_ptr); + gc_check_possible_root(ref); } } } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f47fd2d246..71e2332532 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5521,18 +5521,11 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED, VAR_FETCH|ISSET) if (Z_REFCOUNTED_P(var)) { zend_refcounted *garbage = Z_COUNTED_P(var); + ZVAL_UNDEF(var); if (!--GC_REFCOUNT(garbage)) { - ZVAL_UNDEF(var); zval_dtor_func(garbage); } else { - zval *z = var; - ZVAL_DEREF(z); - if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { - ZVAL_UNDEF(var); - gc_possible_root(Z_COUNTED_P(z)); - } else { - ZVAL_UNDEF(var); - } + gc_check_possible_root(garbage); } } else { ZVAL_UNDEF(var); @@ -7749,18 +7742,19 @@ ZEND_VM_C_LABEL(check_indirect): variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) { - uint32_t refcnt = Z_DELREF_P(variable_ptr); + zend_refcounted *ref = Z_COUNTED_P(variable_ptr); + uint32_t refcnt = --GC_REFCOUNT(ref); if (EXPECTED(variable_ptr != value)) { if (refcnt == 0) { SAVE_OPLINE(); - zval_dtor_func(Z_COUNTED_P(variable_ptr)); + zval_dtor_func(ref); if (UNEXPECTED(EG(exception))) { ZVAL_NULL(variable_ptr); HANDLE_EXCEPTION(); } } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr); + gc_check_possible_root(ref); } } } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index bdc3731262..4e5c0f9816 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7785,18 +7785,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_UNUSED_HA if (Z_REFCOUNTED_P(var)) { zend_refcounted *garbage = Z_COUNTED_P(var); + ZVAL_UNDEF(var); if (!--GC_REFCOUNT(garbage)) { - ZVAL_UNDEF(var); zval_dtor_func(garbage); } else { - zval *z = var; - ZVAL_DEREF(z); - if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { - ZVAL_UNDEF(var); - gc_possible_root(Z_COUNTED_P(z)); - } else { - ZVAL_UNDEF(var); - } + gc_check_possible_root(garbage); } } else { ZVAL_UNDEF(var); @@ -40516,18 +40509,19 @@ check_indirect: variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var); if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) { - uint32_t refcnt = Z_DELREF_P(variable_ptr); + zend_refcounted *ref = Z_COUNTED_P(variable_ptr); + uint32_t refcnt = --GC_REFCOUNT(ref); if (EXPECTED(variable_ptr != value)) { if (refcnt == 0) { SAVE_OPLINE(); - zval_dtor_func(Z_COUNTED_P(variable_ptr)); + zval_dtor_func(ref); if (UNEXPECTED(EG(exception))) { ZVAL_NULL(variable_ptr); HANDLE_EXCEPTION(); } } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr); + gc_check_possible_root(ref); } } } @@ -42720,18 +42714,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_UNUSED_HANDL if (Z_REFCOUNTED_P(var)) { zend_refcounted *garbage = Z_COUNTED_P(var); + ZVAL_UNDEF(var); if (!--GC_REFCOUNT(garbage)) { - ZVAL_UNDEF(var); zval_dtor_func(garbage); } else { - zval *z = var; - ZVAL_DEREF(z); - if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { - ZVAL_UNDEF(var); - gc_possible_root(Z_COUNTED_P(z)); - } else { - ZVAL_UNDEF(var); - } + gc_check_possible_root(garbage); } } else { ZVAL_UNDEF(var); @@ -53909,18 +53896,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMPVAR_UNUSED_H if (Z_REFCOUNTED_P(var)) { zend_refcounted *garbage = Z_COUNTED_P(var); + ZVAL_UNDEF(var); if (!--GC_REFCOUNT(garbage)) { - ZVAL_UNDEF(var); zval_dtor_func(garbage); } else { - zval *z = var; - ZVAL_DEREF(z); - if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { - ZVAL_UNDEF(var); - gc_possible_root(Z_COUNTED_P(z)); - } else { - ZVAL_UNDEF(var); - } + gc_check_possible_root(garbage); } } else { ZVAL_UNDEF(var); |