cvs: ZendEngine2(PHP_5_3) / zend_gc.c
[email protected] ("Dmitry Stogov") Fri, 03 Apr 2009 18:52:21 -0000
| Newsgroups | php.zend-engine.cvs |
|---|---|
| Message-ID | <cvsdmitry1238784741@cvsserver> |
dmitry Fri Apr 3 18:52:21 2009 UTC
Modified files: (Branch: PHP_5_3)
/ZendEngine2 zend_gc.c
Log:
Improved GC speed and reduced stack usage
dmitry-20090403185221.txt
(text/plain, 11.4 KB)
http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_gc.c?r1=1.1.2.21&r2=1.1.2.22&diff_format=u
Index: ZendEngine2/zend_gc.c
diff -u ZendEngine2/zend_gc.c:1.1.2.21 ZendEngine2/zend_gc.c:1.1.2.22
--- ZendEngine2/zend_gc.c:1.1.2.21 Wed Feb 18 12:02:53 2009
+++ ZendEngine2/zend_gc.c Fri Apr 3 18:52:21 2009
@@ -17,7 +17,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: zend_gc.c,v 1.1.2.21 2009/02/18 12:02:53 dmitry Exp $ */
+/* $Id: zend_gc.c,v 1.1.2.22 2009/04/03 18:52:21 dmitry Exp $ */
#include "zend.h"
#include "zend_API.h"
@@ -30,12 +30,6 @@
ZEND_API zend_gc_globals gc_globals;
#endif
-/* Forward declarations */
-static int children_scan_black(zval **pz TSRMLS_DC);
-static int children_mark_grey(zval **pz TSRMLS_DC);
-static int children_collect_white(zval **pz TSRMLS_DC);
-static int children_scan(zval **pz TSRMLS_DC);
-
static void root_buffer_dtor(zend_gc_globals *gc_globals TSRMLS_DC)
{
if (gc_globals->buf) {
@@ -272,18 +266,12 @@
((zval_gc_info*)zv)->u.buffered = NULL;
}
-static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC)
-{
- 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)) {
- zend_hash_apply(Z_OBJPROP_P(pz), (apply_func_t) children_scan_black TSRMLS_CC);
- }
-}
-
static void zval_scan_black(zval *pz TSRMLS_DC)
{
+ Bucket *p;
+
+tail_call:
+ p = NULL;
GC_ZVAL_SET_BLACK(pz);
if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
@@ -291,43 +279,61 @@
obj->refcount++;
if (GC_GET_COLOR(obj->buffered) != GC_BLACK) {
- zobj_scan_black(obj, pz TSRMLS_CC);
+ 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)) {
+ p = Z_OBJPROP_P(pz)->pListHead;
+ }
}
} else if (Z_TYPE_P(pz) == IS_ARRAY) {
if (Z_ARRVAL_P(pz) != &EG(symbol_table)) {
- zend_hash_apply(Z_ARRVAL_P(pz), (apply_func_t) children_scan_black TSRMLS_CC);
+ p = Z_ARRVAL_P(pz)->pListHead;
}
}
-}
-
-static int children_scan_black(zval **pz TSRMLS_DC)
-{
- if (Z_TYPE_PP(pz) != IS_ARRAY || Z_ARRVAL_PP(pz) != &EG(symbol_table)) {
- (*pz)->refcount__gc++;
- }
-
- if (GC_ZVAL_GET_COLOR(*pz) != GC_BLACK) {
- zval_scan_black(*pz TSRMLS_CC);
+ while (p != NULL) {
+ pz = *(zval**)p->pData;
+ 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 (p->pListNext == NULL) {
+ goto tail_call;
+ } else {
+ zval_scan_black(pz TSRMLS_CC);
+ }
+ }
+ p = p->pListNext;
}
-
- return 0;
}
-static void zobj_mark_grey(struct _store_object *obj, zval *pz TSRMLS_DC)
+static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC)
{
- 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)) {
- zend_hash_apply(Z_OBJPROP_P(pz), (apply_func_t) children_mark_grey TSRMLS_CC);
+ Bucket *p;
+
+ 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)) {
+ p = Z_OBJPROP_P(pz)->pListHead;
+ while (p != NULL) {
+ pz = *(zval**)p->pData;
+ 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);
+ }
+ p = p->pListNext;
}
}
}
static void zval_mark_grey(zval *pz TSRMLS_DC)
{
+ Bucket *p;
+
+tail_call:
if (GC_ZVAL_GET_COLOR(pz) != GC_GREY) {
+ p = NULL;
GC_BENCH_INC(zval_marked_grey);
GC_ZVAL_SET_COLOR(pz, GC_GREY);
@@ -335,24 +341,56 @@
struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
obj->refcount--;
- zobj_mark_grey(obj, pz TSRMLS_CC);
+ 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)) {
+ p = Z_OBJPROP_P(pz)->pListHead;
+ }
+ }
} else if (Z_TYPE_P(pz) == IS_ARRAY) {
if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
GC_ZVAL_SET_BLACK(pz);
} else {
- zend_hash_apply(Z_ARRVAL_P(pz), (apply_func_t) children_mark_grey TSRMLS_CC);
+ p = Z_ARRVAL_P(pz)->pListHead;
+ }
+ }
+ while (p != NULL) {
+ pz = *(zval**)p->pData;
+ if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+ pz->refcount__gc--;
+ }
+ if (p->pListNext == NULL) {
+ goto tail_call;
+ } else {
+ zval_mark_grey(pz TSRMLS_CC);
}
+ p = p->pListNext;
}
}
}
-static int children_mark_grey(zval **pz TSRMLS_DC)
+static void zobj_mark_grey(struct _store_object *obj, zval *pz TSRMLS_DC)
{
- if (Z_TYPE_PP(pz) != IS_ARRAY || Z_ARRVAL_PP(pz) != &EG(symbol_table)) {
- (*pz)->refcount__gc--;
+ Bucket *p;
+
+ 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)) {
+ p = Z_OBJPROP_P(pz)->pListHead;
+ while (p != NULL) {
+ pz = *(zval**)p->pData;
+ if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+ pz->refcount__gc--;
+ }
+ zval_mark_grey(pz TSRMLS_CC);
+ p = p->pListNext;
+ }
+ }
}
- zval_mark_grey(*pz TSRMLS_CC);
- return 0;
}
static void gc_mark_roots(TSRMLS_D)
@@ -386,50 +424,75 @@
}
}
-static void zobj_scan(zval *pz TSRMLS_DC)
-{
- if (EG(objects_store).object_buckets) {
- struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
-
- if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
- if (obj->refcount > 0) {
- zobj_scan_black(obj, pz TSRMLS_CC);
- } 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)) {
- zend_hash_apply(Z_OBJPROP_P(pz), (apply_func_t) children_scan TSRMLS_CC);
- }
- }
- }
- }
-}
-
static int zval_scan(zval *pz TSRMLS_DC)
{
+ Bucket *p;
+
+tail_call:
if (GC_ZVAL_GET_COLOR(pz) == GC_GREY) {
+ p = NULL;
if (pz->refcount__gc > 0) {
zval_scan_black(pz TSRMLS_CC);
} else {
GC_ZVAL_SET_COLOR(pz, GC_WHITE);
- if (Z_TYPE_P(pz) == IS_OBJECT) {
- zobj_scan(pz TSRMLS_CC);
+ if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
+ struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
+
+ if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
+ if (obj->refcount > 0) {
+ zobj_scan_black(obj, pz TSRMLS_CC);
+ } 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)) {
+ p = Z_OBJPROP_P(pz)->pListHead;
+ }
+ }
+ }
} else if (Z_TYPE_P(pz) == IS_ARRAY) {
if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
GC_ZVAL_SET_BLACK(pz);
} else {
- zend_hash_apply(Z_ARRVAL_P(pz), (apply_func_t) children_scan TSRMLS_CC);
+ p = Z_ARRVAL_P(pz)->pListHead;
}
}
}
+ while (p != NULL) {
+ if (p->pListNext == NULL) {
+ pz = *(zval**)p->pData;
+ goto tail_call;
+ } else {
+ zval_scan(*(zval**)p->pData TSRMLS_CC);
+ }
+ p = p->pListNext;
+ }
}
return 0;
}
-static int children_scan(zval **pz TSRMLS_DC)
+static void zobj_scan(zval *pz TSRMLS_DC)
{
- zval_scan(*pz TSRMLS_CC);
- return 0;
+ Bucket *p;
+
+ if (EG(objects_store).object_buckets) {
+ struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
+
+ if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
+ if (obj->refcount > 0) {
+ zobj_scan_black(obj, pz TSRMLS_CC);
+ } 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)) {
+ p = Z_OBJPROP_P(pz)->pListHead;
+ while (p != NULL) {
+ zval_scan(*(zval**)p->pData TSRMLS_CC);
+ p = p->pListNext;
+ }
+ }
+ }
+ }
+ }
}
static void gc_scan_roots(TSRMLS_D)
@@ -451,33 +514,29 @@
}
}
-static void zobj_collect_white(zval *pz TSRMLS_DC)
-{
- if (EG(objects_store).object_buckets) {
- zend_object_handle handle = Z_OBJ_HANDLE_P(pz);
- struct _store_object *obj = &EG(objects_store).object_buckets[handle].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)) {
- zend_hash_apply(Z_OBJPROP_P(pz), (apply_func_t) children_collect_white TSRMLS_CC);
- }
- }
- }
-}
-
static void zval_collect_white(zval *pz TSRMLS_DC)
{
+ Bucket *p;
+
+tail_call:
if (((zval_gc_info*)(pz))->u.buffered == (gc_root_buffer*)GC_WHITE) {
+ p = NULL;
GC_ZVAL_SET_BLACK(pz);
- if (Z_TYPE_P(pz) == IS_OBJECT) {
- zobj_collect_white(pz TSRMLS_CC);
+ if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
+ 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)) {
+ p = Z_OBJPROP_P(pz)->pListHead;
+ }
+ }
} else {
if (Z_TYPE_P(pz) == IS_ARRAY) {
- zend_hash_apply(Z_ARRVAL_P(pz), (apply_func_t) children_collect_white TSRMLS_CC);
+ p = Z_ARRVAL_P(pz)->pListHead;
}
}
@@ -485,16 +544,46 @@
pz->refcount__gc++;
((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
GC_G(zval_to_free) = (zval_gc_info*)pz;
+
+ while (p != NULL) {
+ pz = *(zval**)p->pData;
+ if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+ pz->refcount__gc++;
+ }
+ if (p->pListNext == NULL) {
+ goto tail_call;
+ } else {
+ zval_collect_white(pz TSRMLS_CC);
+ }
+ p = p->pListNext;
+ }
}
}
-static int children_collect_white(zval **pz TSRMLS_DC)
+static void zobj_collect_white(zval *pz TSRMLS_DC)
{
- if (Z_TYPE_PP(pz) != IS_ARRAY || Z_ARRVAL_PP(pz) != &EG(symbol_table)) {
- (*pz)->refcount__gc++;
+ Bucket *p;
+
+ if (EG(objects_store).object_buckets) {
+ 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)) {
+ p = Z_OBJPROP_P(pz)->pListHead;
+ while (p != NULL) {
+ pz = *(zval**)p->pData;
+ if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
+ pz->refcount__gc++;
+ }
+ zval_collect_white(pz TSRMLS_CC);
+ p = p->pListNext;
+ }
+ }
+ }
}
- zval_collect_white(*pz TSRMLS_CC);
- return 0;
}
static void gc_collect_roots(TSRMLS_D)