]> granicus.if.org Git - php/commitdiff
Turn IS_TYPE_COLLECTABLE zval flag into GC_COLLECTABLE zend_refcounted flag.
authorDmitry Stogov <dmitry@zend.com>
Fri, 21 Oct 2016 14:47:30 +0000 (17:47 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 21 Oct 2016 14:47:30 +0000 (17:47 +0300)
This simplifies checks and allows reset this flag for "acyclic" arrays and objects.

Zend/zend_execute.c
Zend/zend_execute.h
Zend/zend_gc.h
Zend/zend_hash.c
Zend/zend_objects.c
Zend/zend_objects_API.h
Zend/zend_types.h
Zend/zend_variables.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 8e3d5fd187914f77f492d1b7c36a985c22adc4d0..1bc67fb3cae8753d47d15c934e0144eb15fbc4af 100644 (file)
@@ -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++;
index 82c6a4a4151d8c6cb9174dc1438afddd815e0e51..4d68fea800ae8e950368d4c8d2f6b1592adcb0b3 100644 (file)
@@ -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);
index eb8e500b03513c48256dfd65a4cbfa2071d99d37..be6b8c44fddaec16e5468f90c889602d1a5b64d0 100644 (file)
@@ -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);
        }
 }
 
index e83fc41cf4d62e7d41ec596c45f3250f9a3544c8..c3cae2a831c957a31b8f8717c5e2f9f0ddac6b8d 100644 (file)
@@ -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;
index 1e358996ed6c353812178fe7480d927b88a9aa7a..07b586b6f8f67a0db5f40a8ca72b6a476b3d36af 100644 (file)
@@ -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);
index dbdb02f9845e74cb6ad8eaab632dcf00269b5dde..7dfad70fbcd167a0130a0b2602b95fb177e73404 100644 (file)
@@ -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);
        }
 }
index 2a108877bfd40cbeb9f8407e4ca470988047c2b4..9d4f6a7d4caa7663fe7b48ec0d86dfbff4a2bd2a 100644 (file)
@@ -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))
 
index 0afe68760d47a53a552221ba6003ebd6d8cf276c..b0054eedd3d4b7d90e156ea2099d36655f793d20 100644 (file)
@@ -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);
                }
        }
 }
index f47fd2d2464ca6e52e4fa1f7c7c9ec4e0dc5901c..71e2332532491bc3f0ddad22cfc7c921150ca715 100644 (file)
@@ -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);
                        }
                }
        }
index bdc3731262f8012c69fc6aad4c90bce5ca2ee860..4e5c0f9816f579ffc50e9ab718e885856b97b4a3 100644 (file)
@@ -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);