]> granicus.if.org Git - php/commitdiff
Improved GC to avaid reconstruction of HashTables for object properties
authorDmitry Stogov <dmitry@php.net>
Fri, 15 Apr 2011 09:57:43 +0000 (09:57 +0000)
committerDmitry Stogov <dmitry@php.net>
Fri, 15 Apr 2011 09:57:43 +0000 (09:57 +0000)
Zend/zend_gc.c

index 66a1c74651502974cea0bee223f436e03d5103f2..9de471286d31993a1e2e477138085b3c83463db2 100644 (file)
@@ -275,18 +275,48 @@ tail_call:
        GC_ZVAL_SET_BLACK(pz);
 
        if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
+               zend_object_get_properties_t get_props;
                struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
 
                obj->refcount++;
                if (GC_GET_COLOR(obj->buffered) != GC_BLACK) {
                        GC_SET_BLACK(obj->buffered);
                        if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                    Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
-                               HashTable *props = Z_OBJPROP_P(pz);
-                               if(!props) {
-                                       return;
+                                    (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
+                               if (get_props == zend_std_get_properties) {
+                                       zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
+
+                                       if (!zobj->properties) {
+                                               int i;
+                                               int n = zobj->ce->default_properties_count;
+
+                                               while (n > 0 && !zobj->properties_table[n-1]) n--;
+                                               for (i = 0; i < n; i++) {
+                                                       if (zobj->properties_table[i]) {
+                                                               pz = zobj->properties_table[i];
+                                                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+                                                                       pz->refcount__gc++;
+                                                               }
+                                                               if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
+                                                                       if (i == n - 1) {
+                                                                               goto tail_call;
+                                                                       } else {
+                                                                               zval_scan_black(pz TSRMLS_CC);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                               return;
+                                       } else {
+                                               p = zobj->properties->pListHead;
+                                       }
+                               } else {
+                                       HashTable *props = get_props(pz);
+                                       if(!props) {
+                                               return;
+                                       }
+                                       p = props->pListHead;
                                }
-                               p = props->pListHead;
                        }
                }
        } else if (Z_TYPE_P(pz) == IS_ARRAY) {
@@ -313,15 +343,39 @@ tail_call:
 static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC)
 {
        Bucket *p;
+       zend_object_get_properties_t get_props;
 
        GC_SET_BLACK(obj->buffered);
        if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                    Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
-               HashTable *props = Z_OBJPROP_P(pz);
-               if(!props) {
-                       return;
+                    (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
+               if (get_props == zend_std_get_properties) {
+                       zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
+
+                       if (!zobj->properties) {
+                               int i;
+
+                               for (i = 0; i < zobj->ce->default_properties_count; i++) {
+                                       if (zobj->properties_table[i]) {
+                                               pz = zobj->properties_table[i];
+                                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+                                                       pz->refcount__gc++;
+                                               }
+                                               if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
+                                                       zval_scan_black(pz TSRMLS_CC);
+                                               }
+                    }
+                               }
+                               return;
+                       } else {
+                               p = zobj->properties->pListHead;
+                       }
+               } else {
+                       HashTable *props = get_props(pz);
+                       if(!props) {
+                               return;
+                       }
+                       p = props->pListHead;
                }
-               p = props->pListHead;
                while (p != NULL) {
                        pz = *(zval**)p->pData;
                        if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
@@ -346,6 +400,7 @@ tail_call:
                GC_ZVAL_SET_COLOR(pz, GC_GREY);
 
                if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
+                       zend_object_get_properties_t get_props;
                        struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
 
                        obj->refcount--;
@@ -353,12 +408,39 @@ tail_call:
                                GC_BENCH_INC(zobj_marked_grey);
                                GC_SET_COLOR(obj->buffered, GC_GREY);
                                if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                            Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
-                                       HashTable *props = Z_OBJPROP_P(pz);
-                                       if(!props) {
-                                               return;
+                                            (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
+                                       if (get_props == zend_std_get_properties) {
+                                               zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
+
+                                               if (!zobj->properties) {
+                                                       int i;
+                                                       int n = zobj->ce->default_properties_count;
+
+                                                       while (n > 0 && !zobj->properties_table[n-1]) n--;
+                                                       for (i = 0; i < n; i++) {
+                                                               if (zobj->properties_table[i]) {
+                                                                       pz = zobj->properties_table[i];
+                                                                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+                                                                               pz->refcount__gc--;
+                                                                       }
+                                                                       if (i == n - 1) {
+                                                                               goto tail_call;
+                                                                       } else {
+                                                                               zval_mark_grey(pz TSRMLS_CC);
+                                                                       }
+                                                               }
+                                                       }
+                                                       return;
+                                               } else {
+                                                       p = zobj->properties->pListHead;
+                                               }
+                                       } else {
+                                               HashTable *props = get_props(pz);
+                                               if(!props) {
+                                                       return;
+                                               }
+                                               p = props->pListHead;
                                        }
-                                       p = props->pListHead;
                                }
                        }
                } else if (Z_TYPE_P(pz) == IS_ARRAY) {
@@ -386,17 +468,39 @@ tail_call:
 static void zobj_mark_grey(struct _store_object *obj, zval *pz TSRMLS_DC)
 {
        Bucket *p;
+       zend_object_get_properties_t get_props;
 
        if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
                GC_BENCH_INC(zobj_marked_grey);
                GC_SET_COLOR(obj->buffered, GC_GREY);
                if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                            Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
-                       HashTable *props = Z_OBJPROP_P(pz);
-                       if(!props) {
-                               return;
+                            (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
+                       if (get_props == zend_std_get_properties) {
+                               zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
+
+                               if (!zobj->properties) {
+                                       int i;
+
+                                       for (i = 0; i < zobj->ce->default_properties_count; i++) {
+                                               if (zobj->properties_table[i]) {
+                                                       pz = zobj->properties_table[i];
+                                                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+                                                               pz->refcount__gc--;
+                                                       }
+                                                       zval_mark_grey(pz TSRMLS_CC);
+                       }
+                                       }
+                                       return;
+                               } else {
+                                       p = zobj->properties->pListHead;
+                               }
+                       } else {
+                               HashTable *props = get_props(pz);
+                               if(!props) {
+                                       return;
+                               }
+                               p = props->pListHead;
                        }
-                       p = props->pListHead;
                        while (p != NULL) {
                                pz = *(zval**)p->pData;
                                if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
@@ -442,7 +546,7 @@ static void gc_mark_roots(TSRMLS_D)
        }
 }
 
-static int zval_scan(zval *pz TSRMLS_DC)
+static void zval_scan(zval *pz TSRMLS_DC)
 {
        Bucket *p;
 
@@ -454,6 +558,7 @@ tail_call:
                } else {
                        GC_ZVAL_SET_COLOR(pz, GC_WHITE);
                        if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
+                               zend_object_get_properties_t get_props;
                                struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
 
                                if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
@@ -462,12 +567,36 @@ tail_call:
                                        } else {
                                                GC_SET_COLOR(obj->buffered, GC_WHITE);
                                                if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                                            Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
-                                                       HashTable *props = Z_OBJPROP_P(pz);
-                                                       if(!props) {
-                                                               return 0;
+                                                            (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
+                                                       if (get_props == zend_std_get_properties) {
+                                                               zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
+
+                                                               if (!zobj->properties) {
+                                                                       int i;
+                                                                       int n = zobj->ce->default_properties_count;
+
+                                                                       while (n > 0 && !zobj->properties_table[n-1]) n--;
+                                                                       for (i = 0; i < n; i++) {
+                                                                               if (zobj->properties_table[i]) {
+                                                                                       pz = zobj->properties_table[i];
+                                                                                       if (i == n - 1) {
+                                                                                               goto tail_call;
+                                                                                       } else {
+                                                                                               zval_scan(pz TSRMLS_CC);
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                                       return;
+                                                               } else {
+                                                                       p = zobj->properties->pListHead;
+                                                               }
+                                                       } else {
+                                                               HashTable *props = get_props(pz);
+                                                               if(!props) {
+                                                                       return;
+                                                               }
+                                                               p = props->pListHead;
                                                        }
-                                                       p = props->pListHead;
                                                }
                                        }
                                }
@@ -489,12 +618,12 @@ tail_call:
                        p = p->pListNext;
                }
        }
-       return 0;
 }
 
 static void zobj_scan(zval *pz TSRMLS_DC)
 {
        Bucket *p;
+       zend_object_get_properties_t get_props;
 
        if (EG(objects_store).object_buckets) {
                struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
@@ -505,12 +634,30 @@ static void zobj_scan(zval *pz TSRMLS_DC)
                        } else {
                                GC_SET_COLOR(obj->buffered, GC_WHITE);
                                if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                            Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
-                                       HashTable *props = Z_OBJPROP_P(pz);
-                                       if(!props) {
-                                               return;
+                                            (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
+                                       if (get_props == zend_std_get_properties) {
+                                               zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
+
+                                               if (!zobj->properties) {
+                                                       int i;
+
+                                                       for (i = 0; i < zobj->ce->default_properties_count; i++) {
+                                                               if (zobj->properties_table[i]) {
+                                                                       pz = zobj->properties_table[i];
+                                                                       zval_scan(pz TSRMLS_CC);
+                                       }
+                                                       }
+                                                       return;
+                                               } else {
+                                                       p = zobj->properties->pListHead;
+                                               }
+                                       } else {
+                                               HashTable *props = get_props(pz);
+                                               if(!props) {
+                                                       return;
+                                               }
+                                               p = props->pListHead;
                                        }
-                                       p = props->pListHead;
                                        while (p != NULL) {
                                                zval_scan(*(zval**)p->pData TSRMLS_CC);
                                                p = p->pListNext;
@@ -550,18 +697,52 @@ tail_call:
                GC_ZVAL_SET_BLACK(pz);
 
                if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
+                       zend_object_get_properties_t get_props;
                        struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
 
                        if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
                                GC_SET_BLACK(obj->buffered);
 
                                if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                            Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
-                                       HashTable *props = Z_OBJPROP_P(pz);
-                                       if(!props) {
-                                               return;
+                                            (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
+                                       if (get_props == zend_std_get_properties) {
+                                               zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
+
+                                               if (!zobj->properties) {
+                                                       int i;
+                                                       int n = zobj->ce->default_properties_count;
+
+                                                       while (n > 0 && !zobj->properties_table[n-1]) n--;
+
+                                                       /* restore refcount and put into list to free */
+                                                       pz->refcount__gc++;
+                                                       ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
+                                                       GC_G(zval_to_free) = (zval_gc_info*)pz;
+
+                                                       for (i = 0; i < n; i++) {
+                                                               if (zobj->properties_table[i]) {
+                                                                       pz = zobj->properties_table[i];
+                                                                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+                                                                               pz->refcount__gc++;
+                                                                       }
+                                                                       if (i == n - 1) {
+                                                                               goto tail_call;
+                                                                       } else {
+                                                                               zval_collect_white(pz TSRMLS_CC);
+                                                                       }
+                                                               }
+                                                       }
+                                                       return;
+                                               } else {
+                                                       p = zobj->properties->pListHead;
+                                               }
+                                       } else {
+                                               HashTable *props = get_props(pz);
+                                               if(!props) {
+                                                       return;
+                                               }
+                                               p = props->pListHead;
                                        }
-                                       p = props->pListHead;
                                }
                        }
                } else {
@@ -595,18 +776,40 @@ static void zobj_collect_white(zval *pz TSRMLS_DC)
        Bucket *p;
 
        if (EG(objects_store).object_buckets) {
+               zend_object_get_properties_t get_props;
                struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
 
                if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
                        GC_SET_BLACK(obj->buffered);
 
                        if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                    Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
-                               HashTable *props = Z_OBJPROP_P(pz);
-                               if(!props) {
-                                       return;
+                                    (get_props = Z_OBJ_HANDLER_P(pz, get_properties)) != NULL)) {
+                               if (get_props == zend_std_get_properties) {
+                                       zend_object* zobj = ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj.object));
+
+                                       if (!zobj->properties) {
+                                               int i;
+
+                                               for (i = 0; i < zobj->ce->default_properties_count; i++) {
+                                                       if (zobj->properties_table[i]) {
+                                                               pz = zobj->properties_table[i];
+                                                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+                                                                       pz->refcount__gc++;
+                                                               }
+                                                               zval_collect_white(pz TSRMLS_CC);
+                                                       }
+                                               }
+                                               return;
+                                       } else {
+                                               p = zobj->properties->pListHead;
+                                       }
+                               } else {
+                                       HashTable *props = get_props(pz);
+                                       if(!props) {
+                                               return;
+                                       }
+                                       p = props->pListHead;
                                }
-                               p = props->pListHead;
                                while (p != NULL) {
                                        pz = *(zval**)p->pData;
                                        if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {