cvs: php-src / configure.in /main main.c ZendEngine2 zend.c zend.h zend_builtin_functions.c zend_execute.c zend_execute_API.c zend_gc.c zend_gc.h
zend_objects_API.c zend_objects_API.h zend_operators.c zend_vm_def.h zend_vm_execute.h ZendEngine2/tests gc_001.phpt gc_002.phpt gc_003.phpt
gc_004.phpt gc_005.phpt gc_006.phpt gc_007.phpt gc_008.phpt gc_009.phpt gc_010.phpt gc_011.phpt gc_012.phpt gc_013.phpt gc_014.phpt gc_015.phpt
gc_016.phpt gc_017.phpt gc_018.phpt gc_019.phpt gc_020.phpt gc_021.phpt gc_022.phpt gc_023.phpt gc_024.phpt gc_025.phpt gc_026.phpt
| From: | Dmitry Stogov | Date: | Tue, 22 Jan 2008 09:29:30 +0000 |
| Subject: | cvs: php-src / configure.in /main main.c ZendEngine2 zend.c zend.h zend_builtin_functions.c zend_execute.c zend_execute_API.c zend_gc.c zend_gc.h zend_objects_API.c zend_objects_API.h zend_operators.c zend_vm_def.h zend_vm_execute.h ZendEngine2/tests gc_001.phpt gc_002.phpt gc_003.phpt gc_004.phpt gc_005.phpt gc_006.phpt gc_007.phpt gc_008.phpt gc_009.phpt gc_010.phpt gc_011.phpt gc_012.phpt gc_013.phpt gc_014.phpt gc_015.phpt gc_016.phpt gc_017.phpt gc_018.phpt gc_019.phpt gc_020.phpt gc_021.phpt gc_022.phpt gc_023.phpt gc_024.phpt gc_025.phpt gc_026.phpt |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-47937@lists.php.net to get a copy of this message | ||
dmitry Tue Jan 22 09:29:30 2008 UTC
Modified files:
/php-src configure.in
/ZendEngine2 zend_gc.c zend_gc.h zend.c zend.h
zend_builtin_functions.c zend_execute.c
zend_execute_API.c zend_objects_API.c
zend_objects_API.h zend_operators.c zend_vm_def.h
zend_vm_execute.h
/ZendEngine2/tests gc_001.phpt gc_002.phpt gc_003.phpt gc_004.phpt
gc_005.phpt gc_006.phpt gc_007.phpt gc_008.phpt
gc_009.phpt gc_010.phpt gc_011.phpt gc_012.phpt
gc_013.phpt gc_014.phpt gc_015.phpt gc_016.phpt
gc_017.phpt gc_018.phpt gc_019.phpt gc_020.phpt
gc_021.phpt gc_022.phpt gc_023.phpt gc_024.phpt
gc_025.phpt gc_026.phpt
/php-src/main main.c
Log:
Added garbage collector
http://cvs.php.net/viewvc.cgi/php-src/configure.in?r1=1.642&r2=1.643&diff_format=u Index: php-src/configure.in diff -u php-src/configure.in:1.642 php-src/configure.in:1.643 --- php-src/configure.in:1.642 Fri Oct 5 14:49:40 2007 +++ php-src/configure.in Tue Jan 22 09:29:29 2008 @@ -1,4 +1,4 @@ -## $Id: configure.in,v 1.642 2007/10/05 14:49:40 nlopess Exp $ -*- autoconf -*- +## $Id: configure.in,v 1.643 2008/01/22 09:29:29 dmitry Exp $ -*- autoconf -*- dnl ## Process this file with autoconf to produce a configure script. divert(1) @@ -1235,7 +1235,8 @@ zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ zend_ini.c zend_qsort.c zend_ts_hash.c zend_stream.c \ - zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_strtol.c) + zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c \ + zend_strtol.c zend_gc.c) if test -r "$abs_srcdir/Zend/zend_objects.c"; then PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c \ http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_gc.c?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/zend_gc.c diff -u /dev/null ZendEngine2/zend_gc.c:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/zend_gc.c Tue Jan 22 09:29:29 2008 @@ -0,0 +1,516 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2007 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: David Wang <planetbeing@gmail.com> | + | Dmitry Stogov <dmitry@zend.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: zend_gc.c,v 1.2 2008/01/22 09:29:29 dmitry Exp $ */ + +#include "zend.h" +#include "zend_API.h" + +#define GC_ROOT_BUFFER_MAX_ENTRIES 10000 + +#ifdef ZTS +ZEND_API int gc_globals_id; +#else +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) { + free(gc_globals->buf); + gc_globals->buf = NULL; + } +} + +static void gc_globals_ctor_ex(zend_gc_globals *gc_globals TSRMLS_DC) +{ + gc_globals->gc_enabled = 0; + + gc_globals->buf = NULL; + + gc_globals->roots.next = NULL; + gc_globals->roots.prev = NULL; + gc_globals->unused = NULL; + gc_globals->zval_to_free = NULL; + + gc_globals->gc_runs = 0; + gc_globals->collected = 0; + +#if GC_BENCH + gc_globals->root_buf_length = 0; + gc_globals->root_buf_peak = 0; + gc_globals->zval_possible_root = 0; + gc_globals->zobj_possible_root = 0; + gc_globals->zval_buffered = 0; + gc_globals->zobj_buffered = 0; + gc_globals->zval_remove_from_buffer = 0; + gc_globals->zobj_remove_from_buffer = 0; + gc_globals->zval_marked_grey = 0; + gc_globals->zobj_marked_grey = 0; +#endif +} + +ZEND_API void gc_globals_ctor(TSRMLS_D) +{ +#ifdef ZTS + ts_allocate_id(&gc_globals_id, sizeof(zend_gc_globals), (ts_allocate_ctor) gc_globals_ctor_ex, (ts_allocate_dtor) root_buffer_dtor); +#else + gc_globals_ctor_ex(&gc_globals); +#endif +} + +ZEND_API void gc_globals_dtor(TSRMLS_D) +{ +#ifndef ZTS + root_buffer_dtor(&gc_globals TSRMLS_DC); +#endif +} + +ZEND_API void gc_reset(TSRMLS_D) +{ + int i; + + GC_G(gc_runs) = 0; + GC_G(collected) = 0; + +#if GC_BENCH + GC_G(root_buf_length) = 0; + GC_G(root_buf_peak) = 0; + GC_G(zval_possible_root) = 0; + GC_G(zobj_possible_root) = 0; + GC_G(zval_buffered) = 0; + GC_G(zobj_buffered) = 0; + GC_G(zval_remove_from_buffer) = 0; + GC_G(zobj_remove_from_buffer) = 0; + GC_G(zval_marked_grey) = 0; + GC_G(zobj_marked_grey) = 0; +#endif + + if (GC_G(buf) && + (GC_G(roots).next != &GC_G(roots) || + GC_G(roots).prev != &GC_G(roots))) { + + GC_G(roots).next = &GC_G(roots); + GC_G(roots).prev = &GC_G(roots); + + GC_G(unused) = &GC_G(buf)[0]; + for (i = 0; i < GC_ROOT_BUFFER_MAX_ENTRIES-1; i++) { + GC_G(buf)[i].prev = &GC_G(buf)[i+1]; + } + GC_G(buf)[GC_ROOT_BUFFER_MAX_ENTRIES-1].prev = NULL; + + GC_G(zval_to_free) = NULL; + } +} + +ZEND_API void gc_init(TSRMLS_D) +{ + if (GC_G(buf) == NULL && GC_G(gc_enabled)) { + GC_G(buf) = (gc_root_buffer*) malloc(sizeof(gc_root_buffer) * GC_ROOT_BUFFER_MAX_ENTRIES); + gc_reset(TSRMLS_C); + } +} + +ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC) +{ + if (zv->type == IS_OBJECT) { + GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv); + return; + } + + GC_BENCH_INC(zval_possible_root); + + if (GC_ZVAL_GET_COLOR(zv) != GC_PURPLE) { + GC_ZVAL_SET_PURPLE(zv); + + if (!GC_ZVAL_ADDRESS(zv)) { + gc_root_buffer *newRoot = GC_G(unused); + + if (!newRoot) { + if (!GC_G(gc_enabled)) { + GC_ZVAL_SET_BLACK(zv); + return; + } + zv->refcount__gc++; + gc_collect_cycles(TSRMLS_C); + zv->refcount__gc--; + GC_ZVAL_SET_PURPLE(zv); + newRoot = GC_G(unused); + } + + GC_G(unused) = newRoot->prev; + + newRoot->next = GC_G(roots).next; + newRoot->prev = &GC_G(roots); + GC_G(roots).next->prev = newRoot; + GC_G(roots).next = newRoot; + + GC_ZVAL_SET_ADDRESS(zv, newRoot); + + newRoot->handle = 0; + newRoot->u.pz = zv; + + GC_BENCH_INC(zval_buffered); + GC_BENCH_INC(root_buf_length); + GC_BENCH_PEAK(root_buf_peak, root_buf_length); + } + } +} + +ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC) +{ + struct _store_object *obj; + + if (UNEXPECTED(Z_OBJ_HT_P(zv)->get_properties == NULL)) { + return; + } + + GC_BENCH_INC(zobj_possible_root); + + obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj; + if (GC_GET_COLOR(obj->buffered) != GC_PURPLE) { + GC_SET_PURPLE(obj->buffered); + if (!GC_ADDRESS(obj->buffered)) { + gc_root_buffer *newRoot = GC_G(unused); + + if (!newRoot) { + if (!GC_G(gc_enabled)) { + GC_ZVAL_SET_BLACK(zv); + return; + } + zv->refcount__gc++; + gc_collect_cycles(TSRMLS_C); + zv->refcount__gc--; + GC_SET_PURPLE(obj->buffered); + newRoot = GC_G(unused); + } + + GC_G(unused) = newRoot->prev; + + newRoot->next = GC_G(roots).next; + newRoot->prev = &GC_G(roots); + GC_G(roots).next->prev = newRoot; + GC_G(roots).next = newRoot; + + GC_SET_ADDRESS(obj->buffered, newRoot); + + newRoot->handle = Z_OBJ_HANDLE_P(zv); + newRoot->u.handlers = Z_OBJ_HT_P(zv); + + GC_BENCH_INC(zobj_buffered); + GC_BENCH_INC(root_buf_length); + GC_BENCH_PEAK(root_buf_peak, root_buf_length); + } + } +} + +static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC) +{ + GC_SET_BLACK(obj->buffered); + + if (EXPECTED(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) +{ + GC_ZVAL_SET_BLACK(pz); + + if (Z_TYPE_P(pz) == IS_OBJECT) { + 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) { + zobj_scan_black(obj, pz TSRMLS_CC); + } + } 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); + } + } +} + +static int children_scan_black(zval **pz TSRMLS_DC) +{ + (*pz)->refcount__gc++; + + if (GC_ZVAL_GET_COLOR(*pz) != GC_BLACK) { + zval_scan_black(*pz TSRMLS_CC); + } + + return 0; +} + +static void zobj_mark_grey(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(Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) { + zend_hash_apply(Z_OBJPROP_P(pz), (apply_func_t) children_mark_grey TSRMLS_CC); + } + } +} + +static void zval_mark_grey(zval *pz TSRMLS_DC) +{ + if (GC_ZVAL_GET_COLOR(pz) != GC_GREY) { + GC_BENCH_INC(zval_marked_grey); + GC_ZVAL_SET_COLOR(pz, GC_GREY); + + if (Z_TYPE_P(pz) == IS_OBJECT) { + 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); + } 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); + } + } + } +} + +static int children_mark_grey(zval **pz TSRMLS_DC) +{ + (*pz)->refcount__gc--; + zval_mark_grey(*pz TSRMLS_CC); + return 0; +} + +static void gc_mark_roots(TSRMLS_D) +{ + gc_root_buffer *current = GC_G(roots).next; + + while (current != &GC_G(roots)) { + if (current->handle) { + struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj; + + if (GC_GET_COLOR(obj->buffered) == GC_PURPLE) { + zval z; + + INIT_PZVAL(&z); + Z_OBJ_HANDLE(z) = current->handle; + Z_OBJ_HT(z) = current->u.handlers; + zobj_mark_grey(obj, &z TSRMLS_CC); + } else { + GC_SET_ADDRESS(obj->buffered, NULL); + GC_REMOVE_FROM_BUFFER(current); + } + } else { + if (GC_ZVAL_GET_COLOR(current->u.pz) == GC_PURPLE) { + zval_mark_grey(current->u.pz TSRMLS_CC); + } else { + GC_ZVAL_SET_ADDRESS(current->u.pz, NULL); + GC_REMOVE_FROM_BUFFER(current); + } + } + current = current->next; + } +} + +static void zobj_scan(zval *pz TSRMLS_DC) +{ + 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(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) +{ + if (GC_ZVAL_GET_COLOR(pz) == GC_GREY) { + 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); + } 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); + } + } + } + } + return 0; +} + +static int children_scan(zval **pz TSRMLS_DC) +{ + zval_scan(*pz TSRMLS_CC); + return 0; +} + +static void gc_scan_roots(TSRMLS_D) +{ + gc_root_buffer *current = GC_G(roots).next; + + while (current != &GC_G(roots)) { + if (current->handle) { + zval z; + + INIT_PZVAL(&z); + Z_OBJ_HANDLE(z) = current->handle; + Z_OBJ_HT(z) = current->u.handlers; + zobj_scan(&z TSRMLS_CC); + } else { + zval_scan(current->u.pz TSRMLS_CC); + } + current = current->next; + } +} + +static void zobj_collect_white(zval *pz TSRMLS_DC) +{ + 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(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) +{ + if (((zval_gc_info*)(pz))->u.buffered == (gc_root_buffer*)GC_WHITE) { + GC_ZVAL_SET_BLACK(pz); + + if (Z_TYPE_P(pz) == IS_OBJECT) { + zobj_collect_white(pz TSRMLS_CC); + } else { + if (Z_TYPE_P(pz) == IS_ARRAY) { + if (Z_ARRVAL_P(pz) == &EG(symbol_table)) { + return; + } + zend_hash_apply(Z_ARRVAL_P(pz), (apply_func_t) children_collect_white TSRMLS_CC); + } + /* restore refcount */ + pz->refcount__gc++; + } + + ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free); + GC_G(zval_to_free) = (zval_gc_info*)pz; + } +} + +static int children_collect_white(zval **pz TSRMLS_DC) +{ + zval_collect_white(*pz TSRMLS_CC); + return 0; +} + +static void gc_collect_roots(TSRMLS_D) +{ + gc_root_buffer *current = GC_G(roots).next; + + while (current != &GC_G(roots)) { + if (current->handle) { + struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj; + zval z; + + GC_SET_ADDRESS(obj->buffered, NULL); + INIT_PZVAL(&z); + Z_OBJ_HANDLE(z) = current->handle; + Z_OBJ_HT(z) = current->u.handlers; + zobj_collect_white(&z TSRMLS_CC); + } else { + GC_ZVAL_SET_ADDRESS(current->u.pz, NULL); + zval_collect_white(current->u.pz TSRMLS_CC); + } + + GC_REMOVE_FROM_BUFFER(current); + current = current->next; + } +} + +ZEND_API int gc_collect_cycles(TSRMLS_D) +{ + int count = 0; + + if (GC_G(roots).next != &GC_G(roots)) { + zval_gc_info *p, *q; + + GC_G(gc_runs)++; + GC_G(zval_to_free) = NULL; + gc_mark_roots(TSRMLS_C); + gc_scan_roots(TSRMLS_C); + gc_collect_roots(TSRMLS_C); + + p = GC_G(zval_to_free); + GC_G(zval_to_free) = NULL; + while (p) { + q = p->u.next; + if (Z_TYPE(p->z) == IS_OBJECT) { + if (EG(objects_store).object_buckets && + EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid && + EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 1) { + if (EXPECTED(Z_OBJ_HANDLER(p->z, get_properties) != NULL)) { + Z_OBJPROP(p->z)->pDestructor = NULL; + } + EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1; + zend_objects_store_del_ref_by_handle(Z_OBJ_HANDLE(p->z) TSRMLS_CC); + } + } else { + if (Z_TYPE(p->z) == IS_ARRAY) { + Z_ARRVAL(p->z)->pDestructor = NULL; + } + zval_dtor(&p->z); + } + FREE_ZVAL_EX(&p->z); + p = q; + count++; + } + GC_G(collected) += count; + } + + return count; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_gc.h?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/zend_gc.h diff -u /dev/null ZendEngine2/zend_gc.h:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/zend_gc.h Tue Jan 22 09:29:29 2008 @@ -0,0 +1,245 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2007 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: David Wang <planetbeing@gmail.com> | + | Dmitry Stogov <dmitry@zend.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: zend_gc.h,v 1.2 2008/01/22 09:29:29 dmitry Exp $ */ + +#ifndef ZEND_GC_H +#define ZEND_GC_H + +#ifndef GC_BENCH +# define GC_BENCH 0 +#endif + +#if GC_BENCH +# define GC_BENCH_INC(counter) GC_G(counter)++ +# define GC_BENCH_DEC(counter) GC_G(counter)-- +# define GC_BENCH_PEAK(peak, counter) do { \ + if (GC_G(counter) > GC_G(peak)) { \ + GC_G(peak) = GC_G(counter); \ + } \ + } while (0) +#else +# define GC_BENCH_INC(counter) +# define GC_BENCH_DEC(counter) +# define GC_BENCH_PEAK(peak, counter) +#endif + +#define GC_COLOR 0x03 + +#define GC_BLACK 0x00 +#define GC_WHITE 0x01 +#define GC_GREY 0x02 +#define GC_PURPLE 0x03 + +#define GC_ADDRESS(v) \ + ((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR)) +#define GC_SET_ADDRESS(v, a) \ + (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & GC_COLOR) | ((zend_uintptr_t)(a)))) +#define GC_GET_COLOR(v) \ + (((zend_uintptr_t)(v)) & GC_COLOR) +#define GC_SET_COLOR(v, c) \ + (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & ~GC_COLOR) | (c))) +#define GC_SET_BLACK(v) \ + (v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR)) +#define GC_SET_PURPLE(v) \ + (v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) | GC_PURPLE)) + +#define GC_ZVAL_INIT(z) \ + ((zval_gc_info*)(z))->u.buffered = NULL +#define GC_ZVAL_ADDRESS(v) \ + GC_ADDRESS(((zval_gc_info*)(v))->u.buffered) +#define GC_ZVAL_SET_ADDRESS(v, a) \ + GC_SET_ADDRESS(((zval_gc_info*)(v))->u.buffered, (a)) +#define GC_ZVAL_GET_COLOR(v) \ + GC_GET_COLOR(((zval_gc_info*)(v))->u.buffered) +#define GC_ZVAL_SET_COLOR(v, c) \ + GC_SET_COLOR(((zval_gc_info*)(v))->u.buffered, (c)) +#define GC_ZVAL_SET_BLACK(v) \ + GC_SET_BLACK(((zval_gc_info*)(v))->u.buffered) +#define GC_ZVAL_SET_PURPLE(v) \ + GC_SET_PURPLE(((zval_gc_info*)(v))->u.buffered) + +#define GC_OBJ_INIT(z) \ + (z)->buffered = NULL + +typedef struct _gc_root_buffer { + struct _gc_root_buffer *prev; /* double-linked list */ + struct _gc_root_buffer *next; + zend_object_handle handle; /* must be 0 for zval */ + union { + zval *pz; + zend_object_handlers *handlers; + } u; +} gc_root_buffer; + +typedef struct _zval_gc_info { + zval z; + union { + gc_root_buffer *buffered; + struct _zval_gc_info *next; + } u; +} zval_gc_info; + +typedef struct _zend_gc_globals { + zend_bool gc_enabled; + + gc_root_buffer *buf; /* preallocated arrays of buffers */ + gc_root_buffer roots; /* list of possible roots of cycles */ + gc_root_buffer *unused; /* list of unused buffers */ + + zval_gc_info *zval_to_free; /* temporaryt list of zvals to free */ + + zend_uint gc_runs; + zend_uint collected; + +#if GC_BENCH + zend_uint root_buf_length; + zend_uint root_buf_peak; + zend_uint zval_possible_root; + zend_uint zobj_possible_root; + zend_uint zval_buffered; + zend_uint zobj_buffered; + zend_uint zval_remove_from_buffer; + zend_uint zobj_remove_from_buffer; + zend_uint zval_marked_grey; + zend_uint zobj_marked_grey; +#endif + +} zend_gc_globals; + +#ifdef ZTS +BEGIN_EXTERN_C() +ZEND_API extern int gc_globals_id; +END_EXTERN_C() +#define GC_G(v) TSRMG(gc_globals_id, zend_gc_globals *, v) +#else +#define GC_G(v) (gc_globals.v) +extern ZEND_API zend_gc_globals gc_globals; +#endif + +BEGIN_EXTERN_C() +ZEND_API int gc_collect_cycles(TSRMLS_D); +ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC); +ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC); +ZEND_API void gc_globals_ctor(TSRMLS_D); +ZEND_API void gc_globals_dtor(TSRMLS_D); +ZEND_API void gc_init(TSRMLS_D); +ZEND_API void gc_reset(TSRMLS_D); +END_EXTERN_C() + +#define GC_ZVAL_CHECK_POSSIBLE_ROOT(z) \ + gc_zval_check_possible_root((z) TSRMLS_CC) + +#define GC_REMOVE_FROM_BUFFER(current) \ + gc_remove_from_buffer((current) TSRMLS_CC) + +#define GC_REMOVE_ZVAL_FROM_BUFFER(z) \ + gc_remove_zval_from_buffer(z) + +#define GC_ZOBJ_CHECK_POSSIBLE_ROOT(zobject) \ + do { \ + if (EXPECTED(EG(objects_store).object_buckets != NULL) && \ + EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zobject)].valid) { \ + gc_zobj_possible_root(zobject TSRMLS_CC); \ + } \ + } while (0) + +#define GC_REMOVE_ZOBJ_FROM_BUFFER(obj) \ + do { \ + if (GC_ADDRESS((obj)->buffered)) { \ + GC_BENCH_INC(zobj_remove_from_buffer); \ + GC_REMOVE_FROM_BUFFER(GC_ADDRESS((obj)->buffered)); \ + (obj)->buffered = NULL; \ + } \ + } while (0) + +static zend_always_inline void gc_zval_check_possible_root(zval *z TSRMLS_DC) +{ + if (z->type == IS_ARRAY || z->type == IS_OBJECT) { + gc_zval_possible_root(z TSRMLS_CC); + } +} + +static zend_always_inline void gc_remove_from_buffer(gc_root_buffer *root TSRMLS_DC) +{ + root->next->prev = root->prev; + root->prev->next = root->next; + root->prev = GC_G(unused); + GC_G(unused) = root; + GC_BENCH_DEC(root_buf_length); +} + +static zend_always_inline void gc_remove_zval_from_buffer(zval* z) +{ + gc_root_buffer* root_buffer; + + root_buffer = GC_ADDRESS(((zval_gc_info*)z)->u.buffered); + if (root_buffer) { + TSRMLS_FETCH(); + + GC_BENCH_INC(zval_remove_from_buffer); + GC_REMOVE_FROM_BUFFER(root_buffer); + ((zval_gc_info*)z)->u.buffered = NULL; + } +} + +/* The following macroses override macroses from zend_alloc.h */ +#undef ALLOC_ZVAL +#define ALLOC_ZVAL(z) \ + do { \ + (z) = (zval*)emalloc(sizeof(zval_gc_info)); \ + GC_ZVAL_INIT(z); \ + } while (0) + +#undef FREE_ZVAL +#define FREE_ZVAL(z) \ + do { \ + GC_REMOVE_ZVAL_FROM_BUFFER(z); \ + efree(z); \ + } while (0) + +#undef ALLOC_ZVAL_REL +#define ALLOC_ZVAL_REL(z) \ + do { \ + (z) = (zval*)emalloc_rel(sizeof(zval_gc_info)); \ + GC_ZVAL_INIT(z); \ + } while (0) + +#undef FREE_ZVAL_REL +#define FREE_ZVAL_REL(z) \ + do { \ + GC_REMOVE_ZVAL_FROM_BUFFER(z); \ + efree_rel(z); \ + } while (0) + +#define FREE_ZVAL_EX(z) \ + efree(z) + +#define FREE_ZVAL_REL_EX(z) \ + efree_rel(z) + +#endif /* ZEND_GC_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ http://cvs.php.net/viewvc.cgi/ZendEngine2/zend.c?r1=1.403&r2=1.404&diff_format=u Index: ZendEngine2/zend.c diff -u ZendEngine2/zend.c:1.403 ZendEngine2/zend.c:1.404 --- ZendEngine2/zend.c:1.403 Mon Dec 31 07:12:06 2007 +++ ZendEngine2/zend.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend.c,v 1.403 2007/12/31 07:12:06 sebastian Exp $ */ +/* $Id: zend.c,v 1.404 2008/01/22 09:29:29 dmitry Exp $ */ #include "zend.h" #include "zend_extensions.h" @@ -172,9 +172,23 @@ } /* }}} */ +static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */ +{ + OnUpdateBool(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); + + if (GC_G(gc_enabled)) { + gc_init(TSRMLS_C); + } + + return SUCCESS; +} +/* }}} */ + ZEND_INI_BEGIN() ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) + STD_ZEND_INI_BOOLEAN("zend.enable_gc", "1", ZEND_INI_ALL, OnUpdateGCEnabled, gc_enabled, zend_gc_globals, gc_globals) + /* Unicode .ini entries */ STD_ZEND_INI_BOOLEAN("unicode.semantics", "0", ZEND_INI_SYSTEM, OnUpdateBool, unicode, zend_unicode_globals, unicode_globals) STD_ZEND_INI_ENTRY("unicode.fallback_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, fallback_encoding_conv, zend_unicode_globals, unicode_globals) @@ -1324,6 +1338,7 @@ void zend_activate(TSRMLS_D) /* {{{ */ { + gc_reset(TSRMLS_C); init_unicode_request_globals(TSRMLS_C); init_unicode_strings(); init_compiler(TSRMLS_C); @@ -1377,6 +1392,12 @@ zend_destroy_rsrc_list(&EG(regular_list) TSRMLS_CC); +#ifdef ZEND_DEBUG + if (GC_G(gc_enabled) && !CG(unclean_shutdown)) { + gc_collect_cycles(TSRMLS_C); + } +#endif + zend_try { zend_ini_deactivate(TSRMLS_C); } zend_end_try(); http://cvs.php.net/viewvc.cgi/ZendEngine2/zend.h?r1=1.348&r2=1.349&diff_format=u Index: ZendEngine2/zend.h diff -u ZendEngine2/zend.h:1.348 ZendEngine2/zend.h:1.349 --- ZendEngine2/zend.h:1.348 Mon Dec 31 07:12:06 2007 +++ ZendEngine2/zend.h Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend.h,v 1.348 2007/12/31 07:12:06 sebastian Exp $ */ +/* $Id: zend.h,v 1.349 2008/01/22 09:29:29 dmitry Exp $ */ #ifndef ZEND_H #define ZEND_H @@ -762,6 +762,7 @@ #define ZEND_INTERNAL_ENCODING "UTF-16" +#include "zend_gc.h" #include "zend_operators.h" #include "zend_variables.h" http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_builtin_functions.c?r1=1.359&r2=1.360&diff_format=u Index: ZendEngine2/zend_builtin_functions.c diff -u ZendEngine2/zend_builtin_functions.c:1.359 ZendEngine2/zend_builtin_functions.c:1.360 --- ZendEngine2/zend_builtin_functions.c:1.359 Mon Jan 21 06:36:58 2008 +++ ZendEngine2/zend_builtin_functions.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_builtin_functions.c,v 1.359 2008/01/21 06:36:58 pollita Exp $ */ +/* $Id: zend_builtin_functions.c,v 1.360 2008/01/22 09:29:29 dmitry Exp $ */ #include "zend.h" #include "zend_API.h" @@ -85,6 +85,10 @@ static ZEND_FUNCTION(zend_thread_id); #endif #endif +static ZEND_FUNCTION(gc_collect_cycles); +static ZEND_FUNCTION(gc_enabled); +static ZEND_FUNCTION(gc_enable); +static ZEND_FUNCTION(gc_disable); /* }}} */ #include "zend_arg_defs.c" @@ -148,6 +152,10 @@ ZEND_FE(zend_thread_id, NULL) #endif #endif + ZEND_FE(gc_collect_cycles, NULL) + ZEND_FE(gc_enabled, NULL) + ZEND_FE(gc_enable, NULL) + ZEND_FE(gc_disable, NULL) { NULL, NULL, NULL } }; /* }}} */ @@ -2326,6 +2334,39 @@ } /* }}} */ +/* {{{ proto int gc_collect_cycles(void) + Forces collection of any existing garbage cycles. + Returns number of freed zvals */ +ZEND_FUNCTION(gc_collect_cycles) +{ + RETURN_LONG(gc_collect_cycles(TSRMLS_C)); +} +/* }}} */ + +/* {{{ proto void gc_enabled(void) + Returns status of the circular reference collector */ +ZEND_FUNCTION(gc_enabled) +{ + RETURN_BOOL(GC_G(gc_enabled)); +} +/* }}} */ + +/* {{{ proto void gc_enable(void) + Activates the circular reference collector */ +ZEND_FUNCTION(gc_enable) +{ + zend_alter_ini_entry("zend.enable_gc", sizeof("zend.enable_gc"), "1", sizeof("1")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); +} +/* }}} */ + +/* {{{ proto void gc_disable(void) + Deactivates the circular reference collector */ +ZEND_FUNCTION(gc_disable) +{ + zend_alter_ini_entry("zend.enable_gc", sizeof("zend.enable_gc"), "0", sizeof("0")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); +} +/* }}} */ + /* * Local variables: * tab-width: 4 http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_execute.c?r1=1.783&r2=1.784&diff_format=u Index: ZendEngine2/zend_execute.c diff -u ZendEngine2/zend_execute.c:1.783 ZendEngine2/zend_execute.c:1.784 --- ZendEngine2/zend_execute.c:1.783 Mon Jan 21 19:41:41 2008 +++ ZendEngine2/zend_execute.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_execute.c,v 1.783 2008/01/21 19:41:41 dmitry Exp $ */ +/* $Id: zend_execute.c,v 1.784 2008/01/22 09:29:29 dmitry Exp $ */ #define ZEND_INTENSIVE_DEBUGGING 0 @@ -65,7 +65,7 @@ #define TEMP_VAR_STACK_LIMIT 2000 -static inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, int unref) /* {{{ */ +static inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, int unref TSRMLS_DC) /* {{{ */ { if (!Z_DELREF_P(z)) { Z_SET_REFCOUNT_P(z, 1); @@ -77,6 +77,7 @@ if (unref && Z_ISREF_P(z) && Z_REFCOUNT_P(z) == 1) { Z_UNSET_ISREF_P(z); } + GC_ZVAL_CHECK_POSSIBLE_ROOT(z); } } /* }}} */ @@ -84,14 +85,15 @@ static inline void zend_pzval_unlock_free_func(zval *z) /* {{{ */ { if (!Z_DELREF_P(z)) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); safe_free_zval_ptr(z); } } /* }}} */ -#define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1) -#define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u) +#define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1 TSRMLS_CC) +#define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u TSRMLS_CC) #define PZVAL_UNLOCK_FREE(z) zend_pzval_unlock_free_func(z) #define PZVAL_LOCK(z) Z_ADDREF_P((z)) #define RETURN_VALUE_UNUSED(pzn) (((pzn)->u.EA.type & EXT_TYPE_UNUSED)) @@ -792,6 +794,7 @@ } else { Z_ADDREF_P(value); *variable_ptr_ptr = value; + GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr); zendi_zval_dtor(*variable_ptr); safe_free_zval_ptr(variable_ptr); return value; http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_execute_API.c?r1=1.431&r2=1.432&diff_format=u Index: ZendEngine2/zend_execute_API.c diff -u ZendEngine2/zend_execute_API.c:1.431 ZendEngine2/zend_execute_API.c:1.432 --- ZendEngine2/zend_execute_API.c:1.431 Mon Jan 21 19:41:41 2008 +++ ZendEngine2/zend_execute_API.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_execute_API.c,v 1.431 2008/01/21 19:41:41 dmitry Exp $ */ +/* $Id: zend_execute_API.c,v 1.432 2008/01/22 09:29:29 dmitry Exp $ */ #include <stdio.h> #include <signal.h> @@ -445,10 +445,16 @@ #endif Z_DELREF_PP(zval_ptr); if (Z_REFCOUNT_PP(zval_ptr) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(*zval_ptr); zval_dtor(*zval_ptr); safe_free_zval_ptr_rel(*zval_ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC); - } else if (Z_REFCOUNT_PP(zval_ptr) == 1) { - Z_UNSET_ISREF_PP(zval_ptr); + } else { + TSRMLS_FETCH(); + + if (Z_REFCOUNT_PP(zval_ptr) == 1) { + Z_UNSET_ISREF_PP(zval_ptr); + } + GC_ZVAL_CHECK_POSSIBLE_ROOT(*zval_ptr); } } /* }}} */ http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_objects_API.c?r1=1.68&r2=1.69&diff_format=u Index: ZendEngine2/zend_objects_API.c diff -u ZendEngine2/zend_objects_API.c:1.68 ZendEngine2/zend_objects_API.c:1.69 --- ZendEngine2/zend_objects_API.c:1.68 Mon Dec 31 07:12:07 2007 +++ ZendEngine2/zend_objects_API.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_objects_API.c,v 1.68 2007/12/31 07:12:07 sebastian Exp $ */ +/* $Id: zend_objects_API.c,v 1.69 2008/01/22 09:29:29 dmitry Exp $ */ #include "zend.h" #include "zend_globals.h" @@ -88,6 +88,8 @@ if (objects->object_buckets[i].valid) { struct _store_object *obj = &objects->object_buckets[i].bucket.obj; + GC_REMOVE_ZOBJ_FROM_BUFFER(obj); + objects->object_buckets[i].valid = 0; if (obj->free_storage) { obj->free_storage(obj->object TSRMLS_CC); @@ -119,6 +121,7 @@ EG(objects_store).object_buckets[handle].valid = 1; obj->refcount = 1; + GC_OBJ_INIT(obj); obj->object = object; obj->dtor = dtor?dtor:(zend_objects_store_dtor_t)zend_objects_destroy_object; obj->free_storage = free_storage; @@ -183,6 +186,8 @@ Z_ADDREF_P(zobject); zend_objects_store_del_ref_by_handle(handle TSRMLS_CC); Z_DELREF_P(zobject); + + GC_ZOBJ_CHECK_POSSIBLE_ROOT(zobject); } /* }}} */ @@ -218,6 +223,7 @@ } } if (obj->refcount == 1) { + GC_REMOVE_ZOBJ_FROM_BUFFER(obj); if (obj->free_storage) { zend_try { obj->free_storage(obj->object TSRMLS_CC); http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_objects_API.h?r1=1.29&r2=1.30&diff_format=u Index: ZendEngine2/zend_objects_API.h diff -u ZendEngine2/zend_objects_API.h:1.29 ZendEngine2/zend_objects_API.h:1.30 --- ZendEngine2/zend_objects_API.h:1.29 Mon Dec 31 07:12:07 2007 +++ ZendEngine2/zend_objects_API.h Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_objects_API.h,v 1.29 2007/12/31 07:12:07 sebastian Exp $ */ +/* $Id: zend_objects_API.h,v 1.30 2008/01/22 09:29:29 dmitry Exp $ */ #ifndef ZEND_OBJECTS_API_H #define ZEND_OBJECTS_API_H @@ -38,6 +38,7 @@ zend_objects_free_object_storage_t free_storage; zend_objects_store_clone_t clone; zend_uint refcount; + gc_root_buffer *buffered; } obj; struct { int next; http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_operators.c?r1=1.288&r2=1.289&diff_format=u Index: ZendEngine2/zend_operators.c diff -u ZendEngine2/zend_operators.c:1.288 ZendEngine2/zend_operators.c:1.289 --- ZendEngine2/zend_operators.c:1.288 Mon Jan 21 19:10:51 2008 +++ ZendEngine2/zend_operators.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_operators.c,v 1.288 2008/01/21 19:10:51 dmitry Exp $ */ +/* $Id: zend_operators.c,v 1.289 2008/01/22 09:29:29 dmitry Exp $ */ #include <ctype.h> @@ -1920,6 +1920,7 @@ static inline void zend_free_obj_get_result(zval *op) /* {{{ */ { if (Z_REFCOUNT_P(op) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(op); zval_dtor(op); FREE_ZVAL(op); } else { http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_vm_def.h?r1=1.206&r2=1.207&diff_format=u Index: ZendEngine2/zend_vm_def.h diff -u ZendEngine2/zend_vm_def.h:1.206 ZendEngine2/zend_vm_def.h:1.207 --- ZendEngine2/zend_vm_def.h:1.206 Mon Jan 21 14:26:47 2008 +++ ZendEngine2/zend_vm_def.h Tue Jan 22 09:29:29 2008 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_vm_def.h,v 1.206 2008/01/21 14:26:47 dmitry Exp $ */ +/* $Id: zend_vm_def.h,v 1.207 2008/01/22 09:29:29 dmitry Exp $ */ /* If you change this file, please regenerate the zend_vm_execute.h and * zend_vm_opcodes.h files by running: @@ -349,6 +349,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -587,6 +588,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -677,6 +679,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -1262,6 +1265,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_vm_execute.h?r1=1.212&r2=1.213&diff_format=u Index: ZendEngine2/zend_vm_execute.h diff -u ZendEngine2/zend_vm_execute.h:1.212 ZendEngine2/zend_vm_execute.h:1.213 --- ZendEngine2/zend_vm_execute.h:1.212 Mon Jan 21 14:26:47 2008 +++ ZendEngine2/zend_vm_execute.h Tue Jan 22 09:29:29 2008 @@ -9158,6 +9158,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -9395,6 +9396,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -9485,6 +9487,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -9718,6 +9721,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -10980,6 +10984,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -11218,6 +11223,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -11308,6 +11314,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -11541,6 +11548,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -12708,6 +12716,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -12946,6 +12955,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -13036,6 +13046,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -13269,6 +13280,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -14239,6 +14251,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -15043,6 +15056,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -15280,6 +15294,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -15370,6 +15385,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -15603,6 +15619,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -16650,6 +16667,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -16886,6 +16904,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -16976,6 +16995,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -17055,6 +17075,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -17768,6 +17789,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -18005,6 +18027,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -18095,6 +18118,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -18174,6 +18198,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -18816,6 +18841,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -19053,6 +19079,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -19143,6 +19170,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -19222,6 +19250,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -19864,6 +19893,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -20130,6 +20160,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -20366,6 +20397,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -20456,6 +20488,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -20535,6 +20568,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -22749,6 +22783,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -22985,6 +23020,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -23075,6 +23111,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -23307,6 +23344,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -24397,6 +24435,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -24634,6 +24673,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -24724,6 +24764,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -24956,6 +24997,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -26023,6 +26065,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -26260,6 +26303,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -26350,6 +26394,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -26582,6 +26627,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -27451,6 +27497,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -28163,6 +28210,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -28399,6 +28447,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -28489,6 +28538,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -28721,6 +28771,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_001.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_001.phpt diff -u /dev/null ZendEngine2/tests/gc_001.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_001.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,12 @@ +--TEST-- +GC 001: gc_enable()/gc_diable()/gc_enabled() +--FILE-- +<?php +gc_disable(); +var_dump(gc_enabled()); +gc_enable(); +var_dump(gc_enabled()); +?> +--EXPECT-- +bool(false) +bool(true) http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_002.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_002.phpt diff -u /dev/null ZendEngine2/tests/gc_002.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_002.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,16 @@ +--TEST-- +GC 002: gc_enable()/gc_diable() and ini_get() +--FILE-- +<?php +gc_disable(); +var_dump(gc_enabled()); +echo ini_get('zend.enable_gc') . "\n"; +gc_enable(); +var_dump(gc_enabled()); +echo ini_get('zend.enable_gc') . "\n"; +?> +--EXPECT-- +bool(false) +0 +bool(true) +1 http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_003.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_003.phpt diff -u /dev/null ZendEngine2/tests/gc_003.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_003.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,16 @@ +--TEST-- +GC 003: gc_enabled() and ini_set() +--FILE-- +<?php +ini_set('zend.enable_gc','0'); +var_dump(gc_enabled()); +echo ini_get('zend.enable_gc') . "\n"; +ini_set('zend.enable_gc','1'); +var_dump(gc_enabled()); +echo ini_get('zend.enable_gc') . "\n"; +?> +--EXPECT-- +bool(false) +0 +bool(true) +1 http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_004.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_004.phpt diff -u /dev/null ZendEngine2/tests/gc_004.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_004.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,24 @@ +--TEST-- +GC 004: Simple array cycle +--FILE-- +<?php +$a = array(); +$a[] =& $a; +var_dump($a); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +array(1) { + [0]=> + &array(1) { + [0]=> + &array(1) { + [0]=> + *RECURSION* + } + } +} +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_005.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_005.phpt diff -u /dev/null ZendEngine2/tests/gc_005.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_005.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,31 @@ +--TEST-- +GC 005: Simple object cycle +--FILE-- +<?php +$a = new stdClass(); +$a->a = $a; +var_dump($a); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +object(stdClass)#1 (1) { + ["a"]=> + object(stdClass)#1 (1) { + ["a"]=> + *RECURSION* + } +} +int(1) +ok +--UEXPECT-- +object(stdClass)#1 (1) { + [u"a"]=> + object(stdClass)#1 (1) { + [u"a"]=> + *RECURSION* + } +} +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_006.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_006.phpt diff -u /dev/null ZendEngine2/tests/gc_006.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_006.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,44 @@ +--TEST-- +GC 006: Simple array-object cycle +--FILE-- +<?php +$a = new stdClass(); +$a->a = array(); +$a->a[0] =& $a; +var_dump($a); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +object(stdClass)#1 (1) { + ["a"]=> + array(1) { + [0]=> + &object(stdClass)#1 (1) { + ["a"]=> + array(1) { + [0]=> + *RECURSION* + } + } + } +} +int(2) +ok +--UEXPECT-- +object(stdClass)#1 (1) { + [u"a"]=> + array(1) { + [0]=> + &object(stdClass)#1 (1) { + [u"a"]=> + array(1) { + [0]=> + *RECURSION* + } + } + } +} +int(2) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_007.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_007.phpt diff -u /dev/null ZendEngine2/tests/gc_007.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_007.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,26 @@ +--TEST-- +GC 007: Unreferensed array cycle +--FILE-- +<?php +$a = array(array()); +$a[0][0] =& $a[0]; +var_dump($a[0]); +var_dump(gc_collect_cycles()); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +array(1) { + [0]=> + &array(1) { + [0]=> + &array(1) { + [0]=> + *RECURSION* + } + } +} +int(0) +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_008.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_008.phpt diff -u /dev/null ZendEngine2/tests/gc_008.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_008.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,35 @@ +--TEST-- +GC 008: Unreferensed object cycle +--FILE-- +<?php +$a = new stdClass(); +$a->a = new stdClass(); +$a->a->a = $a->a; +var_dump($a->a); +var_dump(gc_collect_cycles()); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +object(stdClass)#2 (1) { + ["a"]=> + object(stdClass)#2 (1) { + ["a"]=> + *RECURSION* + } +} +int(0) +int(1) +ok +--UEXPECT-- +object(stdClass)#2 (1) { + [u"a"]=> + object(stdClass)#2 (1) { + [u"a"]=> + *RECURSION* + } +} +int(0) +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_009.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_009.phpt diff -u /dev/null ZendEngine2/tests/gc_009.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_009.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,48 @@ +--TEST-- +GC 009: Unreferensed array-object cycle +--FILE-- +<?php +$a = array(); +$a[0] = new stdClass(); +$a[0]->a = array(); +$a[0]->a[0] =& $a[0]; +var_dump($a[0]); +var_dump(gc_collect_cycles()); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +object(stdClass)#1 (1) { + ["a"]=> + array(1) { + [0]=> + &object(stdClass)#1 (1) { + ["a"]=> + array(1) { + [0]=> + *RECURSION* + } + } + } +} +int(0) +int(2) +ok +--UEXPECT-- +object(stdClass)#1 (1) { + [u"a"]=> + array(1) { + [0]=> + &object(stdClass)#1 (1) { + [u"a"]=> + array(1) { + [0]=> + *RECURSION* + } + } + } +} +int(0) +int(2) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_010.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_010.phpt diff -u /dev/null ZendEngine2/tests/gc_010.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_010.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,25 @@ +--TEST-- +GC 010: Cycle with reference to $GLOBALS +--FILE-- +<?php +$a = array(); +$a[] =& $a; +var_dump($a); +$a[] =& $GLOBALS; +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +array(1) { + [0]=> + &array(1) { + [0]=> + &array(1) { + [0]=> + *RECURSION* + } + } +} +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_011.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_011.phpt diff -u /dev/null ZendEngine2/tests/gc_011.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_011.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,39 @@ +--TEST-- +GC 011: GC and destructors +--FILE-- +<?php +class Foo { + public $a; + function __destruct() { + echo __FUNCTION__,"\n"; + } +} +$a = new Foo(); +$a->a = $a; +var_dump($a); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +object(Foo)#1 (1) { + ["a"]=> + object(Foo)#1 (1) { + ["a"]=> + *RECURSION* + } +} +__destruct +int(1) +ok +--UEXPECT-- +object(Foo)#1 (1) { + [u"a"]=> + object(Foo)#1 (1) { + [u"a"]=> + *RECURSION* + } +} +__destruct +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_012.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_012.phpt diff -u /dev/null ZendEngine2/tests/gc_012.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_012.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,17 @@ +--TEST-- +GC 012: collection of many loops at once +--FILE-- +<?php +$a=array(); +for ($i=0; $i < 1000; $i++) { + $a[$i] = array(array()); + $a[$i][0] = & $a[$i]; +} +var_dump(gc_collect_cycles()); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n"; +--EXPECT-- +int(0) +int(1000) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_013.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_013.phpt diff -u /dev/null ZendEngine2/tests/gc_013.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_013.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,16 @@ +--TEST-- +GC 013: Too many cycles in one array +--FILE-- +<?php +$a = array(); +for ($i = 0; $i < 10001; $i++) { + $a[$i] =& $a; +} +$a[] = "xxx"; +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n"; +?> +--EXPECT-- +int(2) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_014.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_014.phpt diff -u /dev/null ZendEngine2/tests/gc_014.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_014.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,18 @@ +--TEST-- +GC 014: Too many cycles in one object +--FILE-- +<?php +$a = new stdClass(); +for ($i = 0; $i < 10001; $i++) { + $b =& $a; + $a->{"a".$i} = $a; +} +unset($b); +$a->b = "xxx"; +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n"; +?> +--EXPECT-- +int(10002) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_015.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_015.phpt diff -u /dev/null ZendEngine2/tests/gc_015.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_015.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,18 @@ +--TEST-- +GC 015: Object as root of cycle +--FILE-- +<?php +$a = new stdClass(); +$c =& $a; +$b = $a; +$a->a = $a; +$a->b = "xxx"; +unset($c); +unset($a); +unset($b); +var_dump(gc_collect_cycles()); +echo "ok\n"; +?> +--EXPECT-- +int(2) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_016.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_016.phpt diff -u /dev/null ZendEngine2/tests/gc_016.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_016.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,24 @@ +--TEST-- +GC 016: nested GC calls +--FILE-- +<?php +class Foo { + public $a; + function __destruct() { + echo "-> "; + $a = array(); + $a[] =& $a; + unset($a); + var_dump(gc_collect_cycles()); + } +} +$a = new Foo(); +$a->a = $a; +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +-> int(1) +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_017.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_017.phpt diff -u /dev/null ZendEngine2/tests/gc_017.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_017.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,47 @@ +--TEST-- +GC 017: GC and destructors with unset +--FILE-- +<?php +class Node { + public $name; + public $children; + public $parent; + function __construct($name) { + $this->name = $name; + $this->children = array(); + $this->parent = null; + } + function insert($node) { + $node->parent = $this; + $this->children[] = $node; + } + function __destruct() { + var_dump($this->name); + unset($this->name); + unset($this->children); + unset($this->parent); + } +} +$a = new Node('A'); +$b = new Node('B'); +$c = new Node('C'); +$a->insert($b); +$a->insert($c); +unset($a); +unset($b); +unset($c); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECTF-- +string(1) "%s" +string(1) "%s" +string(1) "%s" +int(10) +ok +--UEXPECTF-- +unicode(1) "%s" +unicode(1) "%s" +unicode(1) "%s" +int(10) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_018.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_018.phpt diff -u /dev/null ZendEngine2/tests/gc_018.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_018.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,13 @@ +--TEST-- +GC 018: GC detach with assign +--FILE-- +<?php +$a = array(array()); +$a[0][0] =& $a[0]; +$a = 1; +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_019.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_019.phpt diff -u /dev/null ZendEngine2/tests/gc_019.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_019.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,14 @@ +--TEST-- +GC 019: GC detach with assign by reference +--FILE-- +<?php +$a = array(array()); +$a[0][0] =& $a[0]; +$b = 1; +$a =& $b; +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_020.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_020.phpt diff -u /dev/null ZendEngine2/tests/gc_020.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_020.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,15 @@ +--TEST-- +GC 020: GC detach reference with assign +--FILE-- +<?php +$a = array(); +$a[0] =& $a; +$a[1] = array(); +$a[1][0] =& $a[1]; +$a = 1; +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_021.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_021.phpt diff -u /dev/null ZendEngine2/tests/gc_021.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_021.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,16 @@ +--TEST-- +GC 021: GC detach reference with assign by reference +--FILE-- +<?php +$a = array(); +$a[0] =& $a; +$a[1] = array(); +$a[1][0] =& $a[1]; +$b = 1; +$a =& $b; +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +int(2) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_022.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_022.phpt diff -u /dev/null ZendEngine2/tests/gc_022.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_022.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,15 @@ +--TEST-- +GC 022: GC detach reference in executor's PZVAL_UNLOCK() +--INI-- +error_reporting=0 +--FILE-- +<?php +$a = array(array()); +$a[0][0] =& $a[0]; +$s = array(1) + unserialize(serialize(&$a[0])); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_023.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_023.phpt diff -u /dev/null ZendEngine2/tests/gc_023.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_023.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,27 @@ +--TEST-- +GC 023: Root buffer overflow (automatic collection) +--FILE-- +<?php +$a=array(); +for ($i=0; $i < 9999; $i++) { + $a[$i] = array(array()); + $a[$i][0] = & $a[$i]; +} +var_dump(gc_collect_cycles()); +unset($a); +var_dump(gc_collect_cycles()); +$a=array(); +for ($i=0; $i < 10001; $i++) { + $a[$i] = array(array()); + $a[$i][0] = & $a[$i]; +} +var_dump(gc_collect_cycles()); +unset($a); // 10000 zvals collected automatic +var_dump(gc_collect_cycles()); +echo "ok\n"; +--EXPECT-- +int(0) +int(9999) +int(0) +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_024.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_024.phpt diff -u /dev/null ZendEngine2/tests/gc_024.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_024.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,16 @@ +--TEST-- +GC 024: GC and objects with non-standard handlers +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php +$a = new ArrayObject(); +$a[0] = $a; +//var_dump($a); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n"; +?> +--EXPECT-- +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_025.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_025.phpt diff -u /dev/null ZendEngine2/tests/gc_025.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_025.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,11 @@ +--TEST-- +GC 025: Automatic GC on request shutdown +--FILE-- +<?php +$a = array(array()); +$a[0][0] =& $a[0]; +unset($a); +echo "ok\n" +?> +--EXPECT-- +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_026.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_026.phpt diff -u /dev/null ZendEngine2/tests/gc_026.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_026.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,14 @@ +--TEST-- +GC 026: Automatic GC on request shutdown (GC enabled at run-time) +--INI-- +zend.enable_gc=0 +--FILE-- +<?php +gc_enable(); +$a = array(array()); +$a[0][0] =& $a[0]; +unset($a); +echo "ok\n" +?> +--EXPECT-- +ok http://cvs.php.net/viewvc.cgi/php-src/main/main.c?r1=1.755&r2=1.756&diff_format=u Index: php-src/main/main.c diff -u php-src/main/main.c:1.755 php-src/main/main.c:1.756 --- php-src/main/main.c:1.755 Mon Dec 31 07:12:18 2007 +++ php-src/main/main.c Tue Jan 22 09:29:29 2008 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: main.c,v 1.755 2007/12/31 07:12:18 sebastian Exp $ */ +/* $Id: main.c,v 1.756 2008/01/22 09:29:29 dmitry Exp $ */ /* {{{ includes */ @@ -1822,6 +1822,8 @@ ts_allocate_id(&php_win32_core_globals_id, sizeof(php_win32_core_globals), (ts_allocate_ctor) php_win32_core_globals_ctor, (ts_allocate_dtor) php_win32_core_globals_dtor); #endif #endif + gc_globals_ctor(TSRMLS_C); + EG(bailout) = NULL; EG(error_reporting) = E_ALL & ~E_NOTICE; @@ -2070,6 +2072,7 @@ #ifndef ZTS core_globals_dtor(&core_globals TSRMLS_CC); + gc_globals_dtor(TSRMLS_C); #else ts_free_id(core_globals_id); #endif
http://cvs.php.net/viewvc.cgi/php-src/configure.in?r1=1.642&r2=1.643&diff_format=u Index: php-src/configure.in diff -u php-src/configure.in:1.642 php-src/configure.in:1.643 --- php-src/configure.in:1.642 Fri Oct 5 14:49:40 2007 +++ php-src/configure.in Tue Jan 22 09:29:29 2008 @@ -1,4 +1,4 @@ -## $Id: configure.in,v 1.642 2007/10/05 14:49:40 nlopess Exp $ -*- autoconf -*- +## $Id: configure.in,v 1.643 2008/01/22 09:29:29 dmitry Exp $ -*- autoconf -*- dnl ## Process this file with autoconf to produce a configure script. divert(1) @@ -1235,7 +1235,8 @@ zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ zend_ini.c zend_qsort.c zend_ts_hash.c zend_stream.c \ - zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_strtol.c) + zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c \ + zend_strtol.c zend_gc.c) if test -r "$abs_srcdir/Zend/zend_objects.c"; then PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c \ http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_gc.c?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/zend_gc.c diff -u /dev/null ZendEngine2/zend_gc.c:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/zend_gc.c Tue Jan 22 09:29:29 2008 @@ -0,0 +1,516 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2007 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: David Wang <planetbeing@gmail.com> | + | Dmitry Stogov <dmitry@zend.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: zend_gc.c,v 1.2 2008/01/22 09:29:29 dmitry Exp $ */ + +#include "zend.h" +#include "zend_API.h" + +#define GC_ROOT_BUFFER_MAX_ENTRIES 10000 + +#ifdef ZTS +ZEND_API int gc_globals_id; +#else +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) { + free(gc_globals->buf); + gc_globals->buf = NULL; + } +} + +static void gc_globals_ctor_ex(zend_gc_globals *gc_globals TSRMLS_DC) +{ + gc_globals->gc_enabled = 0; + + gc_globals->buf = NULL; + + gc_globals->roots.next = NULL; + gc_globals->roots.prev = NULL; + gc_globals->unused = NULL; + gc_globals->zval_to_free = NULL; + + gc_globals->gc_runs = 0; + gc_globals->collected = 0; + +#if GC_BENCH + gc_globals->root_buf_length = 0; + gc_globals->root_buf_peak = 0; + gc_globals->zval_possible_root = 0; + gc_globals->zobj_possible_root = 0; + gc_globals->zval_buffered = 0; + gc_globals->zobj_buffered = 0; + gc_globals->zval_remove_from_buffer = 0; + gc_globals->zobj_remove_from_buffer = 0; + gc_globals->zval_marked_grey = 0; + gc_globals->zobj_marked_grey = 0; +#endif +} + +ZEND_API void gc_globals_ctor(TSRMLS_D) +{ +#ifdef ZTS + ts_allocate_id(&gc_globals_id, sizeof(zend_gc_globals), (ts_allocate_ctor) gc_globals_ctor_ex, (ts_allocate_dtor) root_buffer_dtor); +#else + gc_globals_ctor_ex(&gc_globals); +#endif +} + +ZEND_API void gc_globals_dtor(TSRMLS_D) +{ +#ifndef ZTS + root_buffer_dtor(&gc_globals TSRMLS_DC); +#endif +} + +ZEND_API void gc_reset(TSRMLS_D) +{ + int i; + + GC_G(gc_runs) = 0; + GC_G(collected) = 0; + +#if GC_BENCH + GC_G(root_buf_length) = 0; + GC_G(root_buf_peak) = 0; + GC_G(zval_possible_root) = 0; + GC_G(zobj_possible_root) = 0; + GC_G(zval_buffered) = 0; + GC_G(zobj_buffered) = 0; + GC_G(zval_remove_from_buffer) = 0; + GC_G(zobj_remove_from_buffer) = 0; + GC_G(zval_marked_grey) = 0; + GC_G(zobj_marked_grey) = 0; +#endif + + if (GC_G(buf) && + (GC_G(roots).next != &GC_G(roots) || + GC_G(roots).prev != &GC_G(roots))) { + + GC_G(roots).next = &GC_G(roots); + GC_G(roots).prev = &GC_G(roots); + + GC_G(unused) = &GC_G(buf)[0]; + for (i = 0; i < GC_ROOT_BUFFER_MAX_ENTRIES-1; i++) { + GC_G(buf)[i].prev = &GC_G(buf)[i+1]; + } + GC_G(buf)[GC_ROOT_BUFFER_MAX_ENTRIES-1].prev = NULL; + + GC_G(zval_to_free) = NULL; + } +} + +ZEND_API void gc_init(TSRMLS_D) +{ + if (GC_G(buf) == NULL && GC_G(gc_enabled)) { + GC_G(buf) = (gc_root_buffer*) malloc(sizeof(gc_root_buffer) * GC_ROOT_BUFFER_MAX_ENTRIES); + gc_reset(TSRMLS_C); + } +} + +ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC) +{ + if (zv->type == IS_OBJECT) { + GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv); + return; + } + + GC_BENCH_INC(zval_possible_root); + + if (GC_ZVAL_GET_COLOR(zv) != GC_PURPLE) { + GC_ZVAL_SET_PURPLE(zv); + + if (!GC_ZVAL_ADDRESS(zv)) { + gc_root_buffer *newRoot = GC_G(unused); + + if (!newRoot) { + if (!GC_G(gc_enabled)) { + GC_ZVAL_SET_BLACK(zv); + return; + } + zv->refcount__gc++; + gc_collect_cycles(TSRMLS_C); + zv->refcount__gc--; + GC_ZVAL_SET_PURPLE(zv); + newRoot = GC_G(unused); + } + + GC_G(unused) = newRoot->prev; + + newRoot->next = GC_G(roots).next; + newRoot->prev = &GC_G(roots); + GC_G(roots).next->prev = newRoot; + GC_G(roots).next = newRoot; + + GC_ZVAL_SET_ADDRESS(zv, newRoot); + + newRoot->handle = 0; + newRoot->u.pz = zv; + + GC_BENCH_INC(zval_buffered); + GC_BENCH_INC(root_buf_length); + GC_BENCH_PEAK(root_buf_peak, root_buf_length); + } + } +} + +ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC) +{ + struct _store_object *obj; + + if (UNEXPECTED(Z_OBJ_HT_P(zv)->get_properties == NULL)) { + return; + } + + GC_BENCH_INC(zobj_possible_root); + + obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj; + if (GC_GET_COLOR(obj->buffered) != GC_PURPLE) { + GC_SET_PURPLE(obj->buffered); + if (!GC_ADDRESS(obj->buffered)) { + gc_root_buffer *newRoot = GC_G(unused); + + if (!newRoot) { + if (!GC_G(gc_enabled)) { + GC_ZVAL_SET_BLACK(zv); + return; + } + zv->refcount__gc++; + gc_collect_cycles(TSRMLS_C); + zv->refcount__gc--; + GC_SET_PURPLE(obj->buffered); + newRoot = GC_G(unused); + } + + GC_G(unused) = newRoot->prev; + + newRoot->next = GC_G(roots).next; + newRoot->prev = &GC_G(roots); + GC_G(roots).next->prev = newRoot; + GC_G(roots).next = newRoot; + + GC_SET_ADDRESS(obj->buffered, newRoot); + + newRoot->handle = Z_OBJ_HANDLE_P(zv); + newRoot->u.handlers = Z_OBJ_HT_P(zv); + + GC_BENCH_INC(zobj_buffered); + GC_BENCH_INC(root_buf_length); + GC_BENCH_PEAK(root_buf_peak, root_buf_length); + } + } +} + +static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC) +{ + GC_SET_BLACK(obj->buffered); + + if (EXPECTED(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) +{ + GC_ZVAL_SET_BLACK(pz); + + if (Z_TYPE_P(pz) == IS_OBJECT) { + 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) { + zobj_scan_black(obj, pz TSRMLS_CC); + } + } 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); + } + } +} + +static int children_scan_black(zval **pz TSRMLS_DC) +{ + (*pz)->refcount__gc++; + + if (GC_ZVAL_GET_COLOR(*pz) != GC_BLACK) { + zval_scan_black(*pz TSRMLS_CC); + } + + return 0; +} + +static void zobj_mark_grey(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(Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) { + zend_hash_apply(Z_OBJPROP_P(pz), (apply_func_t) children_mark_grey TSRMLS_CC); + } + } +} + +static void zval_mark_grey(zval *pz TSRMLS_DC) +{ + if (GC_ZVAL_GET_COLOR(pz) != GC_GREY) { + GC_BENCH_INC(zval_marked_grey); + GC_ZVAL_SET_COLOR(pz, GC_GREY); + + if (Z_TYPE_P(pz) == IS_OBJECT) { + 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); + } 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); + } + } + } +} + +static int children_mark_grey(zval **pz TSRMLS_DC) +{ + (*pz)->refcount__gc--; + zval_mark_grey(*pz TSRMLS_CC); + return 0; +} + +static void gc_mark_roots(TSRMLS_D) +{ + gc_root_buffer *current = GC_G(roots).next; + + while (current != &GC_G(roots)) { + if (current->handle) { + struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj; + + if (GC_GET_COLOR(obj->buffered) == GC_PURPLE) { + zval z; + + INIT_PZVAL(&z); + Z_OBJ_HANDLE(z) = current->handle; + Z_OBJ_HT(z) = current->u.handlers; + zobj_mark_grey(obj, &z TSRMLS_CC); + } else { + GC_SET_ADDRESS(obj->buffered, NULL); + GC_REMOVE_FROM_BUFFER(current); + } + } else { + if (GC_ZVAL_GET_COLOR(current->u.pz) == GC_PURPLE) { + zval_mark_grey(current->u.pz TSRMLS_CC); + } else { + GC_ZVAL_SET_ADDRESS(current->u.pz, NULL); + GC_REMOVE_FROM_BUFFER(current); + } + } + current = current->next; + } +} + +static void zobj_scan(zval *pz TSRMLS_DC) +{ + 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(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) +{ + if (GC_ZVAL_GET_COLOR(pz) == GC_GREY) { + 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); + } 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); + } + } + } + } + return 0; +} + +static int children_scan(zval **pz TSRMLS_DC) +{ + zval_scan(*pz TSRMLS_CC); + return 0; +} + +static void gc_scan_roots(TSRMLS_D) +{ + gc_root_buffer *current = GC_G(roots).next; + + while (current != &GC_G(roots)) { + if (current->handle) { + zval z; + + INIT_PZVAL(&z); + Z_OBJ_HANDLE(z) = current->handle; + Z_OBJ_HT(z) = current->u.handlers; + zobj_scan(&z TSRMLS_CC); + } else { + zval_scan(current->u.pz TSRMLS_CC); + } + current = current->next; + } +} + +static void zobj_collect_white(zval *pz TSRMLS_DC) +{ + 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(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) +{ + if (((zval_gc_info*)(pz))->u.buffered == (gc_root_buffer*)GC_WHITE) { + GC_ZVAL_SET_BLACK(pz); + + if (Z_TYPE_P(pz) == IS_OBJECT) { + zobj_collect_white(pz TSRMLS_CC); + } else { + if (Z_TYPE_P(pz) == IS_ARRAY) { + if (Z_ARRVAL_P(pz) == &EG(symbol_table)) { + return; + } + zend_hash_apply(Z_ARRVAL_P(pz), (apply_func_t) children_collect_white TSRMLS_CC); + } + /* restore refcount */ + pz->refcount__gc++; + } + + ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free); + GC_G(zval_to_free) = (zval_gc_info*)pz; + } +} + +static int children_collect_white(zval **pz TSRMLS_DC) +{ + zval_collect_white(*pz TSRMLS_CC); + return 0; +} + +static void gc_collect_roots(TSRMLS_D) +{ + gc_root_buffer *current = GC_G(roots).next; + + while (current != &GC_G(roots)) { + if (current->handle) { + struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj; + zval z; + + GC_SET_ADDRESS(obj->buffered, NULL); + INIT_PZVAL(&z); + Z_OBJ_HANDLE(z) = current->handle; + Z_OBJ_HT(z) = current->u.handlers; + zobj_collect_white(&z TSRMLS_CC); + } else { + GC_ZVAL_SET_ADDRESS(current->u.pz, NULL); + zval_collect_white(current->u.pz TSRMLS_CC); + } + + GC_REMOVE_FROM_BUFFER(current); + current = current->next; + } +} + +ZEND_API int gc_collect_cycles(TSRMLS_D) +{ + int count = 0; + + if (GC_G(roots).next != &GC_G(roots)) { + zval_gc_info *p, *q; + + GC_G(gc_runs)++; + GC_G(zval_to_free) = NULL; + gc_mark_roots(TSRMLS_C); + gc_scan_roots(TSRMLS_C); + gc_collect_roots(TSRMLS_C); + + p = GC_G(zval_to_free); + GC_G(zval_to_free) = NULL; + while (p) { + q = p->u.next; + if (Z_TYPE(p->z) == IS_OBJECT) { + if (EG(objects_store).object_buckets && + EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid && + EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 1) { + if (EXPECTED(Z_OBJ_HANDLER(p->z, get_properties) != NULL)) { + Z_OBJPROP(p->z)->pDestructor = NULL; + } + EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1; + zend_objects_store_del_ref_by_handle(Z_OBJ_HANDLE(p->z) TSRMLS_CC); + } + } else { + if (Z_TYPE(p->z) == IS_ARRAY) { + Z_ARRVAL(p->z)->pDestructor = NULL; + } + zval_dtor(&p->z); + } + FREE_ZVAL_EX(&p->z); + p = q; + count++; + } + GC_G(collected) += count; + } + + return count; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_gc.h?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/zend_gc.h diff -u /dev/null ZendEngine2/zend_gc.h:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/zend_gc.h Tue Jan 22 09:29:29 2008 @@ -0,0 +1,245 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2007 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: David Wang <planetbeing@gmail.com> | + | Dmitry Stogov <dmitry@zend.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: zend_gc.h,v 1.2 2008/01/22 09:29:29 dmitry Exp $ */ + +#ifndef ZEND_GC_H +#define ZEND_GC_H + +#ifndef GC_BENCH +# define GC_BENCH 0 +#endif + +#if GC_BENCH +# define GC_BENCH_INC(counter) GC_G(counter)++ +# define GC_BENCH_DEC(counter) GC_G(counter)-- +# define GC_BENCH_PEAK(peak, counter) do { \ + if (GC_G(counter) > GC_G(peak)) { \ + GC_G(peak) = GC_G(counter); \ + } \ + } while (0) +#else +# define GC_BENCH_INC(counter) +# define GC_BENCH_DEC(counter) +# define GC_BENCH_PEAK(peak, counter) +#endif + +#define GC_COLOR 0x03 + +#define GC_BLACK 0x00 +#define GC_WHITE 0x01 +#define GC_GREY 0x02 +#define GC_PURPLE 0x03 + +#define GC_ADDRESS(v) \ + ((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR)) +#define GC_SET_ADDRESS(v, a) \ + (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & GC_COLOR) | ((zend_uintptr_t)(a)))) +#define GC_GET_COLOR(v) \ + (((zend_uintptr_t)(v)) & GC_COLOR) +#define GC_SET_COLOR(v, c) \ + (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & ~GC_COLOR) | (c))) +#define GC_SET_BLACK(v) \ + (v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR)) +#define GC_SET_PURPLE(v) \ + (v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) | GC_PURPLE)) + +#define GC_ZVAL_INIT(z) \ + ((zval_gc_info*)(z))->u.buffered = NULL +#define GC_ZVAL_ADDRESS(v) \ + GC_ADDRESS(((zval_gc_info*)(v))->u.buffered) +#define GC_ZVAL_SET_ADDRESS(v, a) \ + GC_SET_ADDRESS(((zval_gc_info*)(v))->u.buffered, (a)) +#define GC_ZVAL_GET_COLOR(v) \ + GC_GET_COLOR(((zval_gc_info*)(v))->u.buffered) +#define GC_ZVAL_SET_COLOR(v, c) \ + GC_SET_COLOR(((zval_gc_info*)(v))->u.buffered, (c)) +#define GC_ZVAL_SET_BLACK(v) \ + GC_SET_BLACK(((zval_gc_info*)(v))->u.buffered) +#define GC_ZVAL_SET_PURPLE(v) \ + GC_SET_PURPLE(((zval_gc_info*)(v))->u.buffered) + +#define GC_OBJ_INIT(z) \ + (z)->buffered = NULL + +typedef struct _gc_root_buffer { + struct _gc_root_buffer *prev; /* double-linked list */ + struct _gc_root_buffer *next; + zend_object_handle handle; /* must be 0 for zval */ + union { + zval *pz; + zend_object_handlers *handlers; + } u; +} gc_root_buffer; + +typedef struct _zval_gc_info { + zval z; + union { + gc_root_buffer *buffered; + struct _zval_gc_info *next; + } u; +} zval_gc_info; + +typedef struct _zend_gc_globals { + zend_bool gc_enabled; + + gc_root_buffer *buf; /* preallocated arrays of buffers */ + gc_root_buffer roots; /* list of possible roots of cycles */ + gc_root_buffer *unused; /* list of unused buffers */ + + zval_gc_info *zval_to_free; /* temporaryt list of zvals to free */ + + zend_uint gc_runs; + zend_uint collected; + +#if GC_BENCH + zend_uint root_buf_length; + zend_uint root_buf_peak; + zend_uint zval_possible_root; + zend_uint zobj_possible_root; + zend_uint zval_buffered; + zend_uint zobj_buffered; + zend_uint zval_remove_from_buffer; + zend_uint zobj_remove_from_buffer; + zend_uint zval_marked_grey; + zend_uint zobj_marked_grey; +#endif + +} zend_gc_globals; + +#ifdef ZTS +BEGIN_EXTERN_C() +ZEND_API extern int gc_globals_id; +END_EXTERN_C() +#define GC_G(v) TSRMG(gc_globals_id, zend_gc_globals *, v) +#else +#define GC_G(v) (gc_globals.v) +extern ZEND_API zend_gc_globals gc_globals; +#endif + +BEGIN_EXTERN_C() +ZEND_API int gc_collect_cycles(TSRMLS_D); +ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC); +ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC); +ZEND_API void gc_globals_ctor(TSRMLS_D); +ZEND_API void gc_globals_dtor(TSRMLS_D); +ZEND_API void gc_init(TSRMLS_D); +ZEND_API void gc_reset(TSRMLS_D); +END_EXTERN_C() + +#define GC_ZVAL_CHECK_POSSIBLE_ROOT(z) \ + gc_zval_check_possible_root((z) TSRMLS_CC) + +#define GC_REMOVE_FROM_BUFFER(current) \ + gc_remove_from_buffer((current) TSRMLS_CC) + +#define GC_REMOVE_ZVAL_FROM_BUFFER(z) \ + gc_remove_zval_from_buffer(z) + +#define GC_ZOBJ_CHECK_POSSIBLE_ROOT(zobject) \ + do { \ + if (EXPECTED(EG(objects_store).object_buckets != NULL) && \ + EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zobject)].valid) { \ + gc_zobj_possible_root(zobject TSRMLS_CC); \ + } \ + } while (0) + +#define GC_REMOVE_ZOBJ_FROM_BUFFER(obj) \ + do { \ + if (GC_ADDRESS((obj)->buffered)) { \ + GC_BENCH_INC(zobj_remove_from_buffer); \ + GC_REMOVE_FROM_BUFFER(GC_ADDRESS((obj)->buffered)); \ + (obj)->buffered = NULL; \ + } \ + } while (0) + +static zend_always_inline void gc_zval_check_possible_root(zval *z TSRMLS_DC) +{ + if (z->type == IS_ARRAY || z->type == IS_OBJECT) { + gc_zval_possible_root(z TSRMLS_CC); + } +} + +static zend_always_inline void gc_remove_from_buffer(gc_root_buffer *root TSRMLS_DC) +{ + root->next->prev = root->prev; + root->prev->next = root->next; + root->prev = GC_G(unused); + GC_G(unused) = root; + GC_BENCH_DEC(root_buf_length); +} + +static zend_always_inline void gc_remove_zval_from_buffer(zval* z) +{ + gc_root_buffer* root_buffer; + + root_buffer = GC_ADDRESS(((zval_gc_info*)z)->u.buffered); + if (root_buffer) { + TSRMLS_FETCH(); + + GC_BENCH_INC(zval_remove_from_buffer); + GC_REMOVE_FROM_BUFFER(root_buffer); + ((zval_gc_info*)z)->u.buffered = NULL; + } +} + +/* The following macroses override macroses from zend_alloc.h */ +#undef ALLOC_ZVAL +#define ALLOC_ZVAL(z) \ + do { \ + (z) = (zval*)emalloc(sizeof(zval_gc_info)); \ + GC_ZVAL_INIT(z); \ + } while (0) + +#undef FREE_ZVAL +#define FREE_ZVAL(z) \ + do { \ + GC_REMOVE_ZVAL_FROM_BUFFER(z); \ + efree(z); \ + } while (0) + +#undef ALLOC_ZVAL_REL +#define ALLOC_ZVAL_REL(z) \ + do { \ + (z) = (zval*)emalloc_rel(sizeof(zval_gc_info)); \ + GC_ZVAL_INIT(z); \ + } while (0) + +#undef FREE_ZVAL_REL +#define FREE_ZVAL_REL(z) \ + do { \ + GC_REMOVE_ZVAL_FROM_BUFFER(z); \ + efree_rel(z); \ + } while (0) + +#define FREE_ZVAL_EX(z) \ + efree(z) + +#define FREE_ZVAL_REL_EX(z) \ + efree_rel(z) + +#endif /* ZEND_GC_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ http://cvs.php.net/viewvc.cgi/ZendEngine2/zend.c?r1=1.403&r2=1.404&diff_format=u Index: ZendEngine2/zend.c diff -u ZendEngine2/zend.c:1.403 ZendEngine2/zend.c:1.404 --- ZendEngine2/zend.c:1.403 Mon Dec 31 07:12:06 2007 +++ ZendEngine2/zend.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend.c,v 1.403 2007/12/31 07:12:06 sebastian Exp $ */ +/* $Id: zend.c,v 1.404 2008/01/22 09:29:29 dmitry Exp $ */ #include "zend.h" #include "zend_extensions.h" @@ -172,9 +172,23 @@ } /* }}} */ +static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */ +{ + OnUpdateBool(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); + + if (GC_G(gc_enabled)) { + gc_init(TSRMLS_C); + } + + return SUCCESS; +} +/* }}} */ + ZEND_INI_BEGIN() ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) + STD_ZEND_INI_BOOLEAN("zend.enable_gc", "1", ZEND_INI_ALL, OnUpdateGCEnabled, gc_enabled, zend_gc_globals, gc_globals) + /* Unicode .ini entries */ STD_ZEND_INI_BOOLEAN("unicode.semantics", "0", ZEND_INI_SYSTEM, OnUpdateBool, unicode, zend_unicode_globals, unicode_globals) STD_ZEND_INI_ENTRY("unicode.fallback_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, fallback_encoding_conv, zend_unicode_globals, unicode_globals) @@ -1324,6 +1338,7 @@ void zend_activate(TSRMLS_D) /* {{{ */ { + gc_reset(TSRMLS_C); init_unicode_request_globals(TSRMLS_C); init_unicode_strings(); init_compiler(TSRMLS_C); @@ -1377,6 +1392,12 @@ zend_destroy_rsrc_list(&EG(regular_list) TSRMLS_CC); +#ifdef ZEND_DEBUG + if (GC_G(gc_enabled) && !CG(unclean_shutdown)) { + gc_collect_cycles(TSRMLS_C); + } +#endif + zend_try { zend_ini_deactivate(TSRMLS_C); } zend_end_try(); http://cvs.php.net/viewvc.cgi/ZendEngine2/zend.h?r1=1.348&r2=1.349&diff_format=u Index: ZendEngine2/zend.h diff -u ZendEngine2/zend.h:1.348 ZendEngine2/zend.h:1.349 --- ZendEngine2/zend.h:1.348 Mon Dec 31 07:12:06 2007 +++ ZendEngine2/zend.h Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend.h,v 1.348 2007/12/31 07:12:06 sebastian Exp $ */ +/* $Id: zend.h,v 1.349 2008/01/22 09:29:29 dmitry Exp $ */ #ifndef ZEND_H #define ZEND_H @@ -762,6 +762,7 @@ #define ZEND_INTERNAL_ENCODING "UTF-16" +#include "zend_gc.h" #include "zend_operators.h" #include "zend_variables.h" http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_builtin_functions.c?r1=1.359&r2=1.360&diff_format=u Index: ZendEngine2/zend_builtin_functions.c diff -u ZendEngine2/zend_builtin_functions.c:1.359 ZendEngine2/zend_builtin_functions.c:1.360 --- ZendEngine2/zend_builtin_functions.c:1.359 Mon Jan 21 06:36:58 2008 +++ ZendEngine2/zend_builtin_functions.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_builtin_functions.c,v 1.359 2008/01/21 06:36:58 pollita Exp $ */ +/* $Id: zend_builtin_functions.c,v 1.360 2008/01/22 09:29:29 dmitry Exp $ */ #include "zend.h" #include "zend_API.h" @@ -85,6 +85,10 @@ static ZEND_FUNCTION(zend_thread_id); #endif #endif +static ZEND_FUNCTION(gc_collect_cycles); +static ZEND_FUNCTION(gc_enabled); +static ZEND_FUNCTION(gc_enable); +static ZEND_FUNCTION(gc_disable); /* }}} */ #include "zend_arg_defs.c" @@ -148,6 +152,10 @@ ZEND_FE(zend_thread_id, NULL) #endif #endif + ZEND_FE(gc_collect_cycles, NULL) + ZEND_FE(gc_enabled, NULL) + ZEND_FE(gc_enable, NULL) + ZEND_FE(gc_disable, NULL) { NULL, NULL, NULL } }; /* }}} */ @@ -2326,6 +2334,39 @@ } /* }}} */ +/* {{{ proto int gc_collect_cycles(void) + Forces collection of any existing garbage cycles. + Returns number of freed zvals */ +ZEND_FUNCTION(gc_collect_cycles) +{ + RETURN_LONG(gc_collect_cycles(TSRMLS_C)); +} +/* }}} */ + +/* {{{ proto void gc_enabled(void) + Returns status of the circular reference collector */ +ZEND_FUNCTION(gc_enabled) +{ + RETURN_BOOL(GC_G(gc_enabled)); +} +/* }}} */ + +/* {{{ proto void gc_enable(void) + Activates the circular reference collector */ +ZEND_FUNCTION(gc_enable) +{ + zend_alter_ini_entry("zend.enable_gc", sizeof("zend.enable_gc"), "1", sizeof("1")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); +} +/* }}} */ + +/* {{{ proto void gc_disable(void) + Deactivates the circular reference collector */ +ZEND_FUNCTION(gc_disable) +{ + zend_alter_ini_entry("zend.enable_gc", sizeof("zend.enable_gc"), "0", sizeof("0")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); +} +/* }}} */ + /* * Local variables: * tab-width: 4 http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_execute.c?r1=1.783&r2=1.784&diff_format=u Index: ZendEngine2/zend_execute.c diff -u ZendEngine2/zend_execute.c:1.783 ZendEngine2/zend_execute.c:1.784 --- ZendEngine2/zend_execute.c:1.783 Mon Jan 21 19:41:41 2008 +++ ZendEngine2/zend_execute.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_execute.c,v 1.783 2008/01/21 19:41:41 dmitry Exp $ */ +/* $Id: zend_execute.c,v 1.784 2008/01/22 09:29:29 dmitry Exp $ */ #define ZEND_INTENSIVE_DEBUGGING 0 @@ -65,7 +65,7 @@ #define TEMP_VAR_STACK_LIMIT 2000 -static inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, int unref) /* {{{ */ +static inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, int unref TSRMLS_DC) /* {{{ */ { if (!Z_DELREF_P(z)) { Z_SET_REFCOUNT_P(z, 1); @@ -77,6 +77,7 @@ if (unref && Z_ISREF_P(z) && Z_REFCOUNT_P(z) == 1) { Z_UNSET_ISREF_P(z); } + GC_ZVAL_CHECK_POSSIBLE_ROOT(z); } } /* }}} */ @@ -84,14 +85,15 @@ static inline void zend_pzval_unlock_free_func(zval *z) /* {{{ */ { if (!Z_DELREF_P(z)) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); safe_free_zval_ptr(z); } } /* }}} */ -#define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1) -#define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u) +#define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1 TSRMLS_CC) +#define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u TSRMLS_CC) #define PZVAL_UNLOCK_FREE(z) zend_pzval_unlock_free_func(z) #define PZVAL_LOCK(z) Z_ADDREF_P((z)) #define RETURN_VALUE_UNUSED(pzn) (((pzn)->u.EA.type & EXT_TYPE_UNUSED)) @@ -792,6 +794,7 @@ } else { Z_ADDREF_P(value); *variable_ptr_ptr = value; + GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr); zendi_zval_dtor(*variable_ptr); safe_free_zval_ptr(variable_ptr); return value; http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_execute_API.c?r1=1.431&r2=1.432&diff_format=u Index: ZendEngine2/zend_execute_API.c diff -u ZendEngine2/zend_execute_API.c:1.431 ZendEngine2/zend_execute_API.c:1.432 --- ZendEngine2/zend_execute_API.c:1.431 Mon Jan 21 19:41:41 2008 +++ ZendEngine2/zend_execute_API.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_execute_API.c,v 1.431 2008/01/21 19:41:41 dmitry Exp $ */ +/* $Id: zend_execute_API.c,v 1.432 2008/01/22 09:29:29 dmitry Exp $ */ #include <stdio.h> #include <signal.h> @@ -445,10 +445,16 @@ #endif Z_DELREF_PP(zval_ptr); if (Z_REFCOUNT_PP(zval_ptr) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(*zval_ptr); zval_dtor(*zval_ptr); safe_free_zval_ptr_rel(*zval_ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC); - } else if (Z_REFCOUNT_PP(zval_ptr) == 1) { - Z_UNSET_ISREF_PP(zval_ptr); + } else { + TSRMLS_FETCH(); + + if (Z_REFCOUNT_PP(zval_ptr) == 1) { + Z_UNSET_ISREF_PP(zval_ptr); + } + GC_ZVAL_CHECK_POSSIBLE_ROOT(*zval_ptr); } } /* }}} */ http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_objects_API.c?r1=1.68&r2=1.69&diff_format=u Index: ZendEngine2/zend_objects_API.c diff -u ZendEngine2/zend_objects_API.c:1.68 ZendEngine2/zend_objects_API.c:1.69 --- ZendEngine2/zend_objects_API.c:1.68 Mon Dec 31 07:12:07 2007 +++ ZendEngine2/zend_objects_API.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_objects_API.c,v 1.68 2007/12/31 07:12:07 sebastian Exp $ */ +/* $Id: zend_objects_API.c,v 1.69 2008/01/22 09:29:29 dmitry Exp $ */ #include "zend.h" #include "zend_globals.h" @@ -88,6 +88,8 @@ if (objects->object_buckets[i].valid) { struct _store_object *obj = &objects->object_buckets[i].bucket.obj; + GC_REMOVE_ZOBJ_FROM_BUFFER(obj); + objects->object_buckets[i].valid = 0; if (obj->free_storage) { obj->free_storage(obj->object TSRMLS_CC); @@ -119,6 +121,7 @@ EG(objects_store).object_buckets[handle].valid = 1; obj->refcount = 1; + GC_OBJ_INIT(obj); obj->object = object; obj->dtor = dtor?dtor:(zend_objects_store_dtor_t)zend_objects_destroy_object; obj->free_storage = free_storage; @@ -183,6 +186,8 @@ Z_ADDREF_P(zobject); zend_objects_store_del_ref_by_handle(handle TSRMLS_CC); Z_DELREF_P(zobject); + + GC_ZOBJ_CHECK_POSSIBLE_ROOT(zobject); } /* }}} */ @@ -218,6 +223,7 @@ } } if (obj->refcount == 1) { + GC_REMOVE_ZOBJ_FROM_BUFFER(obj); if (obj->free_storage) { zend_try { obj->free_storage(obj->object TSRMLS_CC); http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_objects_API.h?r1=1.29&r2=1.30&diff_format=u Index: ZendEngine2/zend_objects_API.h diff -u ZendEngine2/zend_objects_API.h:1.29 ZendEngine2/zend_objects_API.h:1.30 --- ZendEngine2/zend_objects_API.h:1.29 Mon Dec 31 07:12:07 2007 +++ ZendEngine2/zend_objects_API.h Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_objects_API.h,v 1.29 2007/12/31 07:12:07 sebastian Exp $ */ +/* $Id: zend_objects_API.h,v 1.30 2008/01/22 09:29:29 dmitry Exp $ */ #ifndef ZEND_OBJECTS_API_H #define ZEND_OBJECTS_API_H @@ -38,6 +38,7 @@ zend_objects_free_object_storage_t free_storage; zend_objects_store_clone_t clone; zend_uint refcount; + gc_root_buffer *buffered; } obj; struct { int next; http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_operators.c?r1=1.288&r2=1.289&diff_format=u Index: ZendEngine2/zend_operators.c diff -u ZendEngine2/zend_operators.c:1.288 ZendEngine2/zend_operators.c:1.289 --- ZendEngine2/zend_operators.c:1.288 Mon Jan 21 19:10:51 2008 +++ ZendEngine2/zend_operators.c Tue Jan 22 09:29:29 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_operators.c,v 1.288 2008/01/21 19:10:51 dmitry Exp $ */ +/* $Id: zend_operators.c,v 1.289 2008/01/22 09:29:29 dmitry Exp $ */ #include <ctype.h> @@ -1920,6 +1920,7 @@ static inline void zend_free_obj_get_result(zval *op) /* {{{ */ { if (Z_REFCOUNT_P(op) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(op); zval_dtor(op); FREE_ZVAL(op); } else { http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_vm_def.h?r1=1.206&r2=1.207&diff_format=u Index: ZendEngine2/zend_vm_def.h diff -u ZendEngine2/zend_vm_def.h:1.206 ZendEngine2/zend_vm_def.h:1.207 --- ZendEngine2/zend_vm_def.h:1.206 Mon Jan 21 14:26:47 2008 +++ ZendEngine2/zend_vm_def.h Tue Jan 22 09:29:29 2008 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_vm_def.h,v 1.206 2008/01/21 14:26:47 dmitry Exp $ */ +/* $Id: zend_vm_def.h,v 1.207 2008/01/22 09:29:29 dmitry Exp $ */ /* If you change this file, please regenerate the zend_vm_execute.h and * zend_vm_opcodes.h files by running: @@ -349,6 +349,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -587,6 +588,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -677,6 +679,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -1262,6 +1265,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_vm_execute.h?r1=1.212&r2=1.213&diff_format=u Index: ZendEngine2/zend_vm_execute.h diff -u ZendEngine2/zend_vm_execute.h:1.212 ZendEngine2/zend_vm_execute.h:1.213 --- ZendEngine2/zend_vm_execute.h:1.212 Mon Jan 21 14:26:47 2008 +++ ZendEngine2/zend_vm_execute.h Tue Jan 22 09:29:29 2008 @@ -9158,6 +9158,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -9395,6 +9396,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -9485,6 +9487,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -9718,6 +9721,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -10980,6 +10984,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -11218,6 +11223,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -11308,6 +11314,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -11541,6 +11548,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -12708,6 +12716,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -12946,6 +12955,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -13036,6 +13046,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -13269,6 +13280,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -14239,6 +14251,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -15043,6 +15056,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -15280,6 +15294,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -15370,6 +15385,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -15603,6 +15619,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -16650,6 +16667,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -16886,6 +16904,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -16976,6 +16995,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -17055,6 +17075,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -17768,6 +17789,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -18005,6 +18027,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -18095,6 +18118,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -18174,6 +18198,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -18816,6 +18841,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -19053,6 +19079,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -19143,6 +19170,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -19222,6 +19250,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -19864,6 +19893,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -20130,6 +20160,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -20366,6 +20397,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -20456,6 +20488,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -20535,6 +20568,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -22749,6 +22783,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -22985,6 +23020,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -23075,6 +23111,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -23307,6 +23344,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -24397,6 +24435,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -24634,6 +24673,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -24724,6 +24764,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -24956,6 +24997,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -26023,6 +26065,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -26260,6 +26303,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -26350,6 +26394,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -26582,6 +26627,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } @@ -27451,6 +27497,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -28163,6 +28210,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -28399,6 +28447,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -28489,6 +28538,7 @@ zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(z); zval_dtor(z); FREE_ZVAL(z); } @@ -28721,6 +28771,7 @@ if (RETURN_VALUE_UNUSED(&opline->result)) { if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_001.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_001.phpt diff -u /dev/null ZendEngine2/tests/gc_001.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_001.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,12 @@ +--TEST-- +GC 001: gc_enable()/gc_diable()/gc_enabled() +--FILE-- +<?php +gc_disable(); +var_dump(gc_enabled()); +gc_enable(); +var_dump(gc_enabled()); +?> +--EXPECT-- +bool(false) +bool(true) http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_002.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_002.phpt diff -u /dev/null ZendEngine2/tests/gc_002.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_002.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,16 @@ +--TEST-- +GC 002: gc_enable()/gc_diable() and ini_get() +--FILE-- +<?php +gc_disable(); +var_dump(gc_enabled()); +echo ini_get('zend.enable_gc') . "\n"; +gc_enable(); +var_dump(gc_enabled()); +echo ini_get('zend.enable_gc') . "\n"; +?> +--EXPECT-- +bool(false) +0 +bool(true) +1 http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_003.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_003.phpt diff -u /dev/null ZendEngine2/tests/gc_003.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_003.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,16 @@ +--TEST-- +GC 003: gc_enabled() and ini_set() +--FILE-- +<?php +ini_set('zend.enable_gc','0'); +var_dump(gc_enabled()); +echo ini_get('zend.enable_gc') . "\n"; +ini_set('zend.enable_gc','1'); +var_dump(gc_enabled()); +echo ini_get('zend.enable_gc') . "\n"; +?> +--EXPECT-- +bool(false) +0 +bool(true) +1 http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_004.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_004.phpt diff -u /dev/null ZendEngine2/tests/gc_004.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_004.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,24 @@ +--TEST-- +GC 004: Simple array cycle +--FILE-- +<?php +$a = array(); +$a[] =& $a; +var_dump($a); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +array(1) { + [0]=> + &array(1) { + [0]=> + &array(1) { + [0]=> + *RECURSION* + } + } +} +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_005.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_005.phpt diff -u /dev/null ZendEngine2/tests/gc_005.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_005.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,31 @@ +--TEST-- +GC 005: Simple object cycle +--FILE-- +<?php +$a = new stdClass(); +$a->a = $a; +var_dump($a); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +object(stdClass)#1 (1) { + ["a"]=> + object(stdClass)#1 (1) { + ["a"]=> + *RECURSION* + } +} +int(1) +ok +--UEXPECT-- +object(stdClass)#1 (1) { + [u"a"]=> + object(stdClass)#1 (1) { + [u"a"]=> + *RECURSION* + } +} +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_006.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_006.phpt diff -u /dev/null ZendEngine2/tests/gc_006.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_006.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,44 @@ +--TEST-- +GC 006: Simple array-object cycle +--FILE-- +<?php +$a = new stdClass(); +$a->a = array(); +$a->a[0] =& $a; +var_dump($a); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +object(stdClass)#1 (1) { + ["a"]=> + array(1) { + [0]=> + &object(stdClass)#1 (1) { + ["a"]=> + array(1) { + [0]=> + *RECURSION* + } + } + } +} +int(2) +ok +--UEXPECT-- +object(stdClass)#1 (1) { + [u"a"]=> + array(1) { + [0]=> + &object(stdClass)#1 (1) { + [u"a"]=> + array(1) { + [0]=> + *RECURSION* + } + } + } +} +int(2) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_007.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_007.phpt diff -u /dev/null ZendEngine2/tests/gc_007.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_007.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,26 @@ +--TEST-- +GC 007: Unreferensed array cycle +--FILE-- +<?php +$a = array(array()); +$a[0][0] =& $a[0]; +var_dump($a[0]); +var_dump(gc_collect_cycles()); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +array(1) { + [0]=> + &array(1) { + [0]=> + &array(1) { + [0]=> + *RECURSION* + } + } +} +int(0) +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_008.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_008.phpt diff -u /dev/null ZendEngine2/tests/gc_008.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_008.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,35 @@ +--TEST-- +GC 008: Unreferensed object cycle +--FILE-- +<?php +$a = new stdClass(); +$a->a = new stdClass(); +$a->a->a = $a->a; +var_dump($a->a); +var_dump(gc_collect_cycles()); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +object(stdClass)#2 (1) { + ["a"]=> + object(stdClass)#2 (1) { + ["a"]=> + *RECURSION* + } +} +int(0) +int(1) +ok +--UEXPECT-- +object(stdClass)#2 (1) { + [u"a"]=> + object(stdClass)#2 (1) { + [u"a"]=> + *RECURSION* + } +} +int(0) +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_009.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_009.phpt diff -u /dev/null ZendEngine2/tests/gc_009.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_009.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,48 @@ +--TEST-- +GC 009: Unreferensed array-object cycle +--FILE-- +<?php +$a = array(); +$a[0] = new stdClass(); +$a[0]->a = array(); +$a[0]->a[0] =& $a[0]; +var_dump($a[0]); +var_dump(gc_collect_cycles()); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +object(stdClass)#1 (1) { + ["a"]=> + array(1) { + [0]=> + &object(stdClass)#1 (1) { + ["a"]=> + array(1) { + [0]=> + *RECURSION* + } + } + } +} +int(0) +int(2) +ok +--UEXPECT-- +object(stdClass)#1 (1) { + [u"a"]=> + array(1) { + [0]=> + &object(stdClass)#1 (1) { + [u"a"]=> + array(1) { + [0]=> + *RECURSION* + } + } + } +} +int(0) +int(2) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_010.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_010.phpt diff -u /dev/null ZendEngine2/tests/gc_010.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_010.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,25 @@ +--TEST-- +GC 010: Cycle with reference to $GLOBALS +--FILE-- +<?php +$a = array(); +$a[] =& $a; +var_dump($a); +$a[] =& $GLOBALS; +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +array(1) { + [0]=> + &array(1) { + [0]=> + &array(1) { + [0]=> + *RECURSION* + } + } +} +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_011.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_011.phpt diff -u /dev/null ZendEngine2/tests/gc_011.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_011.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,39 @@ +--TEST-- +GC 011: GC and destructors +--FILE-- +<?php +class Foo { + public $a; + function __destruct() { + echo __FUNCTION__,"\n"; + } +} +$a = new Foo(); +$a->a = $a; +var_dump($a); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +object(Foo)#1 (1) { + ["a"]=> + object(Foo)#1 (1) { + ["a"]=> + *RECURSION* + } +} +__destruct +int(1) +ok +--UEXPECT-- +object(Foo)#1 (1) { + [u"a"]=> + object(Foo)#1 (1) { + [u"a"]=> + *RECURSION* + } +} +__destruct +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_012.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_012.phpt diff -u /dev/null ZendEngine2/tests/gc_012.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_012.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,17 @@ +--TEST-- +GC 012: collection of many loops at once +--FILE-- +<?php +$a=array(); +for ($i=0; $i < 1000; $i++) { + $a[$i] = array(array()); + $a[$i][0] = & $a[$i]; +} +var_dump(gc_collect_cycles()); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n"; +--EXPECT-- +int(0) +int(1000) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_013.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_013.phpt diff -u /dev/null ZendEngine2/tests/gc_013.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_013.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,16 @@ +--TEST-- +GC 013: Too many cycles in one array +--FILE-- +<?php +$a = array(); +for ($i = 0; $i < 10001; $i++) { + $a[$i] =& $a; +} +$a[] = "xxx"; +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n"; +?> +--EXPECT-- +int(2) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_014.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_014.phpt diff -u /dev/null ZendEngine2/tests/gc_014.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_014.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,18 @@ +--TEST-- +GC 014: Too many cycles in one object +--FILE-- +<?php +$a = new stdClass(); +for ($i = 0; $i < 10001; $i++) { + $b =& $a; + $a->{"a".$i} = $a; +} +unset($b); +$a->b = "xxx"; +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n"; +?> +--EXPECT-- +int(10002) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_015.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_015.phpt diff -u /dev/null ZendEngine2/tests/gc_015.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_015.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,18 @@ +--TEST-- +GC 015: Object as root of cycle +--FILE-- +<?php +$a = new stdClass(); +$c =& $a; +$b = $a; +$a->a = $a; +$a->b = "xxx"; +unset($c); +unset($a); +unset($b); +var_dump(gc_collect_cycles()); +echo "ok\n"; +?> +--EXPECT-- +int(2) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_016.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_016.phpt diff -u /dev/null ZendEngine2/tests/gc_016.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_016.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,24 @@ +--TEST-- +GC 016: nested GC calls +--FILE-- +<?php +class Foo { + public $a; + function __destruct() { + echo "-> "; + $a = array(); + $a[] =& $a; + unset($a); + var_dump(gc_collect_cycles()); + } +} +$a = new Foo(); +$a->a = $a; +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +-> int(1) +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_017.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_017.phpt diff -u /dev/null ZendEngine2/tests/gc_017.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_017.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,47 @@ +--TEST-- +GC 017: GC and destructors with unset +--FILE-- +<?php +class Node { + public $name; + public $children; + public $parent; + function __construct($name) { + $this->name = $name; + $this->children = array(); + $this->parent = null; + } + function insert($node) { + $node->parent = $this; + $this->children[] = $node; + } + function __destruct() { + var_dump($this->name); + unset($this->name); + unset($this->children); + unset($this->parent); + } +} +$a = new Node('A'); +$b = new Node('B'); +$c = new Node('C'); +$a->insert($b); +$a->insert($c); +unset($a); +unset($b); +unset($c); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECTF-- +string(1) "%s" +string(1) "%s" +string(1) "%s" +int(10) +ok +--UEXPECTF-- +unicode(1) "%s" +unicode(1) "%s" +unicode(1) "%s" +int(10) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_018.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_018.phpt diff -u /dev/null ZendEngine2/tests/gc_018.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_018.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,13 @@ +--TEST-- +GC 018: GC detach with assign +--FILE-- +<?php +$a = array(array()); +$a[0][0] =& $a[0]; +$a = 1; +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_019.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_019.phpt diff -u /dev/null ZendEngine2/tests/gc_019.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_019.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,14 @@ +--TEST-- +GC 019: GC detach with assign by reference +--FILE-- +<?php +$a = array(array()); +$a[0][0] =& $a[0]; +$b = 1; +$a =& $b; +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_020.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_020.phpt diff -u /dev/null ZendEngine2/tests/gc_020.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_020.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,15 @@ +--TEST-- +GC 020: GC detach reference with assign +--FILE-- +<?php +$a = array(); +$a[0] =& $a; +$a[1] = array(); +$a[1][0] =& $a[1]; +$a = 1; +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_021.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_021.phpt diff -u /dev/null ZendEngine2/tests/gc_021.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_021.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,16 @@ +--TEST-- +GC 021: GC detach reference with assign by reference +--FILE-- +<?php +$a = array(); +$a[0] =& $a; +$a[1] = array(); +$a[1][0] =& $a[1]; +$b = 1; +$a =& $b; +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +int(2) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_022.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_022.phpt diff -u /dev/null ZendEngine2/tests/gc_022.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_022.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,15 @@ +--TEST-- +GC 022: GC detach reference in executor's PZVAL_UNLOCK() +--INI-- +error_reporting=0 +--FILE-- +<?php +$a = array(array()); +$a[0][0] =& $a[0]; +$s = array(1) + unserialize(serialize(&$a[0])); +var_dump(gc_collect_cycles()); +echo "ok\n" +?> +--EXPECT-- +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_023.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_023.phpt diff -u /dev/null ZendEngine2/tests/gc_023.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_023.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,27 @@ +--TEST-- +GC 023: Root buffer overflow (automatic collection) +--FILE-- +<?php +$a=array(); +for ($i=0; $i < 9999; $i++) { + $a[$i] = array(array()); + $a[$i][0] = & $a[$i]; +} +var_dump(gc_collect_cycles()); +unset($a); +var_dump(gc_collect_cycles()); +$a=array(); +for ($i=0; $i < 10001; $i++) { + $a[$i] = array(array()); + $a[$i][0] = & $a[$i]; +} +var_dump(gc_collect_cycles()); +unset($a); // 10000 zvals collected automatic +var_dump(gc_collect_cycles()); +echo "ok\n"; +--EXPECT-- +int(0) +int(9999) +int(0) +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_024.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_024.phpt diff -u /dev/null ZendEngine2/tests/gc_024.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_024.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,16 @@ +--TEST-- +GC 024: GC and objects with non-standard handlers +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php +$a = new ArrayObject(); +$a[0] = $a; +//var_dump($a); +unset($a); +var_dump(gc_collect_cycles()); +echo "ok\n"; +?> +--EXPECT-- +int(1) +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_025.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_025.phpt diff -u /dev/null ZendEngine2/tests/gc_025.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_025.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,11 @@ +--TEST-- +GC 025: Automatic GC on request shutdown +--FILE-- +<?php +$a = array(array()); +$a[0][0] =& $a[0]; +unset($a); +echo "ok\n" +?> +--EXPECT-- +ok http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/gc_026.phpt?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/tests/gc_026.phpt diff -u /dev/null ZendEngine2/tests/gc_026.phpt:1.2 --- /dev/null Tue Jan 22 09:29:30 2008 +++ ZendEngine2/tests/gc_026.phpt Tue Jan 22 09:29:29 2008 @@ -0,0 +1,14 @@ +--TEST-- +GC 026: Automatic GC on request shutdown (GC enabled at run-time) +--INI-- +zend.enable_gc=0 +--FILE-- +<?php +gc_enable(); +$a = array(array()); +$a[0][0] =& $a[0]; +unset($a); +echo "ok\n" +?> +--EXPECT-- +ok http://cvs.php.net/viewvc.cgi/php-src/main/main.c?r1=1.755&r2=1.756&diff_format=u Index: php-src/main/main.c diff -u php-src/main/main.c:1.755 php-src/main/main.c:1.756 --- php-src/main/main.c:1.755 Mon Dec 31 07:12:18 2007 +++ php-src/main/main.c Tue Jan 22 09:29:29 2008 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: main.c,v 1.755 2007/12/31 07:12:18 sebastian Exp $ */ +/* $Id: main.c,v 1.756 2008/01/22 09:29:29 dmitry Exp $ */ /* {{{ includes */ @@ -1822,6 +1822,8 @@ ts_allocate_id(&php_win32_core_globals_id, sizeof(php_win32_core_globals), (ts_allocate_ctor) php_win32_core_globals_ctor, (ts_allocate_dtor) php_win32_core_globals_dtor); #endif #endif + gc_globals_ctor(TSRMLS_C); + EG(bailout) = NULL; EG(error_reporting) = E_ALL & ~E_NOTICE; @@ -2070,6 +2072,7 @@ #ifndef ZTS core_globals_dtor(&core_globals TSRMLS_CC); + gc_globals_dtor(TSRMLS_C); #else ts_free_id(core_globals_id); #endif