? Zend/zend_gc.c ? Zend/zend_gc.h ? pear/scripts Index: configure.in =================================================================== RCS file: /repository/php-src/configure.in,v retrieving revision 1.579.2.52.2.77.2.5 diff -u -p -d -r1.579.2.52.2.77.2.5 configure.in --- configure.in 5 Oct 2007 15:00:05 -0000 1.579.2.52.2.77.2.5 +++ configure.in 8 Oct 2007 04:33:08 -0000 @@ -1325,7 +1325,7 @@ PHP_ADD_SOURCES(Zend, \ 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_multibyte.c zend_ts_hash.c zend_stream.c \ - zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c) + zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.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 \ Index: Zend/zend.c =================================================================== RCS file: /repository/ZendEngine2/zend.c,v retrieving revision 1.308.2.12.2.35.2.1 diff -u -p -d -r1.308.2.12.2.35.2.1 zend.c --- Zend/zend.c 7 Oct 2007 05:22:02 -0000 1.308.2.12.2.35.2.1 +++ Zend/zend.c 8 Oct 2007 04:33:09 -0000 @@ -74,9 +74,42 @@ static ZEND_INI_MH(OnUpdateErrorReportin return SUCCESS; } +static ZEND_INI_MH(OnUpdateGCEnabled) +{ + zend_bool *p; +#ifndef ZTS + char *base = (char *) mh_arg2; +#else + char *base; + + base = (char *) ts_resource(*((int *) mh_arg2)); +#endif + + p = (zend_bool *) (base+(size_t) mh_arg1); + + if (new_value_length==2 && strcasecmp("on", new_value)==0) { + *p = (zend_bool) 1; + } + else if (new_value_length==3 && strcasecmp("yes", new_value)==0) { + *p = (zend_bool) 1; + } + else if (new_value_length==4 && strcasecmp("true", new_value)==0) { + *p = (zend_bool) 1; + } + else { + *p = (zend_bool) atoi(new_value); + } + + if (GC_G(gc_enabled)) { + gc_root_buffer_ctor(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) STD_ZEND_INI_BOOLEAN("zend.ze1_compatibility_mode", "0", ZEND_INI_ALL, OnUpdateBool, ze1_compatibility_mode, zend_executor_globals, executor_globals) #ifdef ZEND_MULTIBYTE STD_ZEND_INI_BOOLEAN("detect_unicode", "1", ZEND_INI_ALL, OnUpdateBool, detect_unicode, zend_compiler_globals, compiler_globals) Index: Zend/zend.h =================================================================== RCS file: /repository/ZendEngine2/zend.h,v retrieving revision 1.293.2.11.2.9.2.7 diff -u -p -d -r1.293.2.11.2.9.2.7 zend.h --- Zend/zend.h 7 Oct 2007 05:22:02 -0000 1.293.2.11.2.9.2.7 +++ Zend/zend.h 8 Oct 2007 04:33:09 -0000 @@ -220,8 +220,23 @@ char *alloca (); #define ZTS_V 0 #endif +#if defined(__GNUC__) +#define always_inline inline __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define always_inline __forceinline +#else +#define always_inline inline +#endif + +#if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX) +# define EXPECTED(condition) __builtin_expect(condition, 1) +# define UNEXPECTED(condition) __builtin_expect(condition, 0) +#else +# define EXPECTED(condition) (condition) +# define UNEXPECTED(condition) (condition) +#endif + #include "zend_errors.h" -#include "zend_alloc.h" #include "zend_types.h" @@ -242,7 +257,7 @@ char *alloca (); #define SUCCESS 0 #define FAILURE -1 /* this MUST stay a negative number, or it may affect functions! */ - +#include "../TSRM/TSRM.h" #include "zend_hash.h" #include "zend_ts_hash.h" #include "zend_llist.h" @@ -328,45 +343,6 @@ struct _zval_struct { #define Z_UNSET_ISREF(z) Z_UNSET_ISREF_P(&(z)) #define Z_SET_ISREF_TO(z, isref) Z_SET_ISREF_TO_P(&(z), isref) -#if defined(__GNUC__) -#define always_inline inline __attribute__((always_inline)) -#elif defined(_MSC_VER) -#define always_inline __forceinline -#else -#define always_inline inline -#endif - -static always_inline zend_uint zval_refcount_p(zval* pz) { - return pz->refcount__gc; -} - -static always_inline zend_uint zval_set_refcount_p(zval* pz, zend_uint rc) { - return pz->refcount__gc = rc; -} - -static always_inline zend_uint zval_addref_p(zval* pz) { - return ++pz->refcount__gc; -} - -static always_inline zend_uint zval_delref_p(zval* pz) { - return --pz->refcount__gc; -} - -static always_inline zend_bool zval_isref_p(zval* pz) { - return pz->is_ref__gc; -} - -static always_inline zend_bool zval_set_isref_p(zval* pz) { - return pz->is_ref__gc = 1; -} - -static always_inline zend_bool zval_unset_isref_p(zval* pz) { - return pz->is_ref__gc = 0; -} -static always_inline zend_bool zval_set_isref_to_p(zval* pz, zend_bool isref) { - return pz->is_ref__gc = isref; -} - /* excpt.h on Digital Unix 4.0 defines function_table */ #undef function_table @@ -713,9 +689,45 @@ END_EXTERN_C() #define ZEND_MAX_RESERVED_RESOURCES 4 +#include "zend_gc.h" +#include "zend_alloc.h" #include "zend_operators.h" #include "zend_variables.h" +static always_inline zend_uint zval_refcount_p(zval* pz) { + return pz->refcount__gc; +} + +static always_inline zend_uint zval_set_refcount_p(zval* pz, zend_uint rc) { + INIT_GC(pz); + return pz->refcount__gc = rc; +} + +static always_inline zend_uint zval_addref_p(zval* pz) { + Z_SET_BLACK_P(pz); + return ++pz->refcount__gc; +} + +static always_inline zend_uint zval_delref_p(zval* pz) { + return --pz->refcount__gc; +} + +static always_inline zend_bool zval_isref_p(zval* pz) { + return pz->is_ref__gc >= 0x80; +} + +static always_inline zend_bool zval_set_isref_p(zval* pz) { + return (pz->is_ref__gc |= 0x80); +} + +static always_inline zend_bool zval_unset_isref_p(zval* pz) { + return (pz->is_ref__gc &= 0x7f); +} + +static always_inline zend_bool zval_set_isref_to_p(zval* pz, zend_bool isref) { + return (pz->is_ref__gc = (isref != 0) ? (pz->is_ref__gc | 0x80) : (pz->is_ref__gc & 0x7f)); +} + #endif /* ZEND_H */ /* Index: Zend/zend_alloc.c =================================================================== RCS file: /repository/ZendEngine2/zend_alloc.c,v retrieving revision 1.144.2.3.2.43.2.1 diff -u -p -d -r1.144.2.3.2.43.2.1 zend_alloc.c --- Zend/zend_alloc.c 29 Sep 2007 10:37:29 -0000 1.144.2.3.2.43.2.1 +++ Zend/zend_alloc.c 8 Oct 2007 04:33:09 -0000 @@ -79,12 +79,7 @@ void zend_debug_alloc_output(char *forma #endif #if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX) -# define EXPECTED(condition) __builtin_expect(condition, 1) -# define UNEXPECTED(condition) __builtin_expect(condition, 0) static void zend_mm_panic(const char *message) __attribute__ ((noreturn)); -#else -# define EXPECTED(condition) (condition) -# define UNEXPECTED(condition) (condition) #endif static void zend_mm_panic(const char *message) Index: Zend/zend_alloc.h =================================================================== RCS file: /repository/ZendEngine2/zend_alloc.h,v retrieving revision 1.63.2.2.2.12.2.1 diff -u -p -d -r1.63.2.2.2.12.2.1 zend_alloc.h --- Zend/zend_alloc.h 29 Sep 2007 10:37:29 -0000 1.63.2.2.2.12.2.1 +++ Zend/zend_alloc.h 8 Oct 2007 04:33:09 -0000 @@ -149,29 +149,45 @@ END_EXTERN_C() /* Macroses for zend_fast_cache.h compatibility */ #define ZEND_FAST_ALLOC(p, type, fc_type) \ - (p) = (type *) emalloc(sizeof(type)) + (p) = ZEND_FAST_ALLOC_EX(type, fc_type) #define ZEND_FAST_FREE(p, fc_type) \ efree(p) #define ZEND_FAST_ALLOC_REL(p, type, fc_type) \ - (p) = (type *) emalloc_rel(sizeof(type)) + (p) = ZEND_FAST_ALLOC_REL_EX(type, fc_type) + +#define ZEND_FAST_ALLOC_EX(type, fc_type) \ + (type *) emalloc(sizeof(type)) + +#define ZEND_FAST_ALLOC_REL_EX(type, fc_type) \ + (type *) emalloc_rel(sizeof(type)) #define ZEND_FAST_FREE_REL(p, fc_type) \ efree_rel(p) /* fast cache for zval's */ #define ALLOC_ZVAL(z) \ - ZEND_FAST_ALLOC(z, zval, ZVAL_CACHE_LIST) + (z) = ADD_GC_INFO(ZEND_FAST_ALLOC_REL_EX(zval_gc_info, ZVAL_CACHE_LIST)); -#define FREE_ZVAL(z) \ +#define FREE_ZVAL_EX(z) \ + REMOVE_GC_INFO(z); \ ZEND_FAST_FREE(z, ZVAL_CACHE_LIST) +#define FREE_ZVAL_REL_EX(z) \ + REMOVE_GC_INFO(z); \ + ZEND_FAST_FREE_REL(z, ZVAL_CACHE_LIST) + +#define FREE_ZVAL(z) \ + REMOVE_ZVAL_FROM_BUFFER(z); \ + FREE_ZVAL_EX(z) + #define ALLOC_ZVAL_REL(z) \ - ZEND_FAST_ALLOC_REL(z, zval, ZVAL_CACHE_LIST) + (z) = ADD_GC_INFO(ZEND_FAST_ALLOC_REL_EX(zval_gc_info, ZVAL_CACHE_LIST)); #define FREE_ZVAL_REL(z) \ - ZEND_FAST_FREE_REL(z, ZVAL_CACHE_LIST) + REMOVE_ZVAL_FROM_BUFFER(z); \ + FREE_ZVAL_REL_EX(z) /* fast cache for HashTables */ #define ALLOC_HASHTABLE(ht) \ Index: Zend/zend_builtin_functions.c =================================================================== RCS file: /repository/ZendEngine2/zend_builtin_functions.c,v retrieving revision 1.277.2.12.2.25.2.5 diff -u -p -d -r1.277.2.12.2.25.2.5 zend_builtin_functions.c --- Zend/zend_builtin_functions.c 7 Oct 2007 05:22:02 -0000 1.277.2.12.2.25.2.5 +++ Zend/zend_builtin_functions.c 8 Oct 2007 04:33:10 -0000 @@ -85,6 +85,9 @@ static ZEND_FUNCTION(zend_test_func); static ZEND_FUNCTION(zend_thread_id); #endif #endif +static ZEND_FUNCTION(gc_collect_cycles); +static ZEND_FUNCTION(enable_gc); +static ZEND_FUNCTION(disable_gc); #include "zend_arg_defs.c" @@ -148,6 +151,9 @@ static const zend_function_entry builtin ZEND_FE(zend_thread_id, NULL) #endif #endif + ZEND_FE(gc_collect_cycles, NULL) + ZEND_FE(enable_gc, NULL) + ZEND_FE(disable_gc, NULL) { NULL, NULL, NULL } }; @@ -166,6 +172,32 @@ ZEND_FUNCTION(zend_version) } /* }}} */ +/* {{{ proto void gc_collect_cycles(void) + Forces collection of any existing garbage cycles */ +ZEND_FUNCTION(gc_collect_cycles) +{ + if(EXPECTED(GC_G(gc_enabled))) { + gc_collect_cycles(TSRMLS_C); + } +} +/* }}} */ + +/* {{{ proto void enable_gc(void) + Activates the circular reference collector */ +ZEND_FUNCTION(enable_gc) +{ + GC_G(gc_enabled) = 1; + gc_root_buffer_ctor(TSRMLS_C); +} +/* }}} */ + +/* {{{ proto void disable_gc(void) + Deactivates the circular reference collector */ +ZEND_FUNCTION(disable_gc) +{ + GC_G(gc_enabled) = 0; +} +/* }}} */ /* {{{ proto int func_num_args(void) Get the number of arguments that were passed to the function */ @@ -1150,6 +1182,9 @@ ZEND_FUNCTION(crash) memcpy(nowhere, "something", sizeof("something")); } #endif +static ZEND_FUNCTION(gc_collect_cycles); +static ZEND_FUNCTION(enable_gc); +static ZEND_FUNCTION(disable_gc); #endif /* ZEND_DEBUG */ Index: Zend/zend_execute.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute.c,v retrieving revision 1.716.2.12.2.24.2.4 diff -u -p -d -r1.716.2.12.2.24.2.4 zend_execute.c --- Zend/zend_execute.c 7 Oct 2007 05:22:03 -0000 1.716.2.12.2.24.2.4 +++ Zend/zend_execute.c 8 Oct 2007 04:33:10 -0000 @@ -66,6 +66,8 @@ static void zend_extension_fcall_end_han static inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, int unref) { + int failure = 0; + if (!Z_DELREF_P(z)) { Z_SET_REFCOUNT_P(z, 1); Z_UNSET_ISREF_P(z); @@ -76,15 +78,25 @@ static inline void zend_pzval_unlock_fun if (unref && Z_ISREF_P(z) && Z_REFCOUNT_P(z) == 1) { Z_UNSET_ISREF_P(z); } + CHECK_POSSIBLE_ROOT(z) + if (failure) { + zend_bailout(); + } } } static inline void zend_pzval_unlock_free_func(zval *z) { + int failure = 0; if (!Z_DELREF_P(z)) { zval_dtor(z); safe_free_zval_ptr(z); - } + } else { + CHECK_POSSIBLE_ROOT(z) + if (failure) { + zend_bailout(); + } + } } #define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1) @@ -393,6 +405,7 @@ static inline void zend_switch_free(zend static void zend_assign_to_variable_reference(zval **variable_ptr_ptr, zval **value_ptr_ptr TSRMLS_DC) { + int failure = 0; zval *variable_ptr; zval *value_ptr; @@ -410,6 +423,7 @@ static void zend_assign_to_variable_refe if (!PZVAL_IS_REF(value_ptr)) { /* break it away */ Z_DELREF_P(value_ptr); + CHECK_POSSIBLE_ROOT(value_ptr); if (Z_REFCOUNT_P(value_ptr)>0) { ALLOC_ZVAL(*value_ptr_ptr); **value_ptr_ptr = *value_ptr; @@ -430,7 +444,9 @@ static void zend_assign_to_variable_refe } else if (variable_ptr==EG(uninitialized_zval_ptr) || Z_REFCOUNT_P(variable_ptr)>2) { /* we need to separate */ - Z_SET_REFCOUNT_P(variable_ptr, Z_REFCOUNT_P(variable_ptr) - 2); + Z_DELREF_P(variable_ptr); + Z_DELREF_P(variable_ptr); + CHECK_POSSIBLE_ROOT(variable_ptr); ALLOC_ZVAL(*variable_ptr_ptr); **variable_ptr_ptr = *variable_ptr; zval_copy_ctor(*variable_ptr_ptr); @@ -439,6 +455,10 @@ static void zend_assign_to_variable_refe } Z_SET_ISREF_PP(variable_ptr_ptr); } + + if (failure) { + zend_bailout(); + } } /* this should modify object only if it's empty */ @@ -642,6 +662,7 @@ static inline void zend_assign_to_object static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2, zval *value, int type, temp_variable *Ts TSRMLS_DC) { + int failure = 0; zend_free_op free_op1; zval **variable_ptr_ptr = get_zval_ptr_ptr(op1, Ts, &free_op1, BP_VAR_W); zval *variable_ptr; @@ -796,11 +817,13 @@ static inline void zend_assign_to_variab if (type!=IS_TMP_VAR) { zendi_zval_copy_ctor(*variable_ptr); Z_DELREF_P(value); + CHECK_POSSIBLE_ROOT(value); } zendi_zval_dtor(garbage); } } else { Z_DELREF_P(variable_ptr); + CHECK_POSSIBLE_ROOT(variable_ptr); if (Z_REFCOUNT_P(variable_ptr)==0) { switch (type) { case IS_CV: @@ -871,6 +894,7 @@ done_setting_var: static inline void zend_receive(zval **variable_ptr_ptr, zval *value TSRMLS_DC) { + int failure = 0; zval *variable_ptr = *variable_ptr_ptr; if (EG(ze1_compatibility_mode) && Z_TYPE_P(value) == IS_OBJECT) { @@ -896,9 +920,14 @@ static inline void zend_receive(zval **v } } else { Z_DELREF_P(variable_ptr); + CHECK_POSSIBLE_ROOT(variable_ptr); *variable_ptr_ptr = value; Z_ADDREF_P(value); } + + if (failure) { + zend_bailout(); + } } /* Utility Functions for Extensions */ Index: Zend/zend_execute_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute_API.c,v retrieving revision 1.331.2.20.2.24.2.8 diff -u -p -d -r1.331.2.20.2.24.2.8 zend_execute_API.c --- Zend/zend_execute_API.c 7 Oct 2007 05:22:03 -0000 1.331.2.20.2.24.2.8 +++ Zend/zend_execute_API.c 8 Oct 2007 04:33:10 -0000 @@ -220,6 +220,9 @@ void shutdown_destructors(TSRMLS_D) { void shutdown_executor(TSRMLS_D) { + zend_bool gc_active_orig = GC_G(gc_active); + GC_G(gc_active) = 0; + zend_try { /* Removed because this can not be safely done, e.g. in this situation: Object 1 creates object 2 @@ -322,6 +325,8 @@ void shutdown_executor(TSRMLS_D) } } zend_end_try(); EG(active) = 0; + + GC_G(gc_active) = gc_active_orig; } @@ -407,6 +412,8 @@ ZEND_API zend_bool zend_is_executing(TSR ZEND_API void _zval_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC) { + int failure = 0; + #if DEBUG_ZEND>=2 printf("Reducing refcount for %x (%x): %d->%d\n", *zval_ptr, zval_ptr, Z_REFCOUNT_PP(zval_ptr), Z_REFCOUNT_PP(zval_ptr)-1); #endif @@ -414,15 +421,22 @@ ZEND_API void _zval_ptr_dtor(zval **zval if (Z_REFCOUNT_PP(zval_ptr)==0) { 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) { - if ((*zval_ptr)->type == IS_OBJECT) { - TSRMLS_FETCH(); + } else { + TSRMLS_FETCH(); - if (EG(ze1_compatibility_mode)) { - return; + if (Z_REFCOUNT_PP(zval_ptr) == 1) { + if ((*zval_ptr)->type == IS_OBJECT) { + if (EG(ze1_compatibility_mode)) { + return; + } } + Z_UNSET_ISREF_PP(zval_ptr); + } + + CHECK_POSSIBLE_ROOT(*zval_ptr); + if (failure) { + zend_bailout(); } - Z_UNSET_ISREF_PP(zval_ptr); } } Index: Zend/zend_hash.c =================================================================== RCS file: /repository/ZendEngine2/zend_hash.c,v retrieving revision 1.121.2.4.2.8.2.1 diff -u -p -d -r1.121.2.4.2.8.2.1 zend_hash.c --- Zend/zend_hash.c 27 Sep 2007 18:00:37 -0000 1.121.2.4.2.8.2.1 +++ Zend/zend_hash.c 8 Oct 2007 04:33:10 -0000 @@ -86,6 +86,27 @@ static void _zend_is_inconsistent(HashTa (ht)->nApplyCount--; \ } +ZEND_API void zend_hash_destroy_no_destructor(HashTable *ht) +{ + Bucket *p, *q; + + IS_CONSISTENT(ht); + + SET_INCONSISTENT(HT_IS_DESTROYING); + + p = ht->pListHead; + while (p != NULL) { + q = p; + p = p->pListNext; + if (q->pData != &q->pDataPtr) { + pefree(q->pData, ht->persistent); + } + pefree(q, ht->persistent); + } + pefree(ht->arBuckets, ht->persistent); + + SET_INCONSISTENT(HT_DESTROYED); +} #define ZEND_HASH_IF_FULL_DO_RESIZE(ht) \ if ((ht)->nNumOfElements > (ht)->nTableSize) { \ Index: Zend/zend_hash.h =================================================================== RCS file: /repository/ZendEngine2/zend_hash.h,v retrieving revision 1.78.2.2.2.2.2.1 diff -u -p -d -r1.78.2.2.2.2.2.1 zend_hash.h --- Zend/zend_hash.h 27 Sep 2007 18:00:37 -0000 1.78.2.2.2.2.2.1 +++ Zend/zend_hash.h 8 Oct 2007 04:33:10 -0000 @@ -93,6 +93,7 @@ BEGIN_EXTERN_C() ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC); ZEND_API int _zend_hash_init_ex(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC); ZEND_API void zend_hash_destroy(HashTable *ht); +ZEND_API void zend_hash_destroy_no_destructor(HashTable *ht); ZEND_API void zend_hash_clean(HashTable *ht); #define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent) _zend_hash_init((ht), (nSize), (pHashFunction), (pDestructor), (persistent) ZEND_FILE_LINE_CC) #define zend_hash_init_ex(ht, nSize, pHashFunction, pDestructor, persistent, bApplyProtection) _zend_hash_init_ex((ht), (nSize), (pHashFunction), (pDestructor), (persistent), (bApplyProtection) ZEND_FILE_LINE_CC) Index: Zend/zend_objects.c =================================================================== RCS file: /repository/ZendEngine2/zend_objects.c,v retrieving revision 1.56.2.3.2.6.2.1 diff -u -p -d -r1.56.2.3.2.6.2.1 zend_objects.c --- Zend/zend_objects.c 7 Oct 2007 05:22:03 -0000 1.56.2.3.2.6.2.1 +++ Zend/zend_objects.c 8 Oct 2007 04:33:11 -0000 @@ -42,7 +42,11 @@ ZEND_API void zend_object_std_dtor(zend_ FREE_HASHTABLE(object->guards); } if (object->properties) { - zend_hash_destroy(object->properties); + if (GC_G(gc_active == 0)) + zend_hash_destroy(object->properties); + else + zend_hash_destroy_no_destructor(object->properties); + FREE_HASHTABLE(object->properties); } } Index: Zend/zend_objects_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_objects_API.c,v retrieving revision 1.47.2.6.2.6.2.1 diff -u -p -d -r1.47.2.6.2.6.2.1 zend_objects_API.c --- Zend/zend_objects_API.c 7 Oct 2007 05:22:03 -0000 1.47.2.6.2.6.2.1 +++ Zend/zend_objects_API.c 8 Oct 2007 04:33:11 -0000 @@ -1,3 +1,4 @@ + /* +----------------------------------------------------------------------+ | Zend Engine | @@ -84,6 +85,8 @@ ZEND_API void zend_objects_store_free_ob if (objects->object_buckets[i].valid) { struct _store_object *obj = &objects->object_buckets[i].bucket.obj; + REMOVE_ZEND_OBJECT_FROM_BUFFER(obj); + objects->object_buckets[i].valid = 0; if (obj->free_storage) { obj->free_storage(obj->object TSRMLS_CC); @@ -116,6 +119,7 @@ ZEND_API zend_object_handle zend_objects EG(objects_store).object_buckets[handle].valid = 1; obj->refcount = 1; + INIT_GC_OBJ(obj); obj->object = object; obj->dtor = dtor?dtor:(zend_objects_store_dtor_t)zend_objects_destroy_object; obj->free_storage = free_storage; @@ -140,6 +144,7 @@ ZEND_API void zend_objects_store_add_ref zend_object_handle handle = Z_OBJ_HANDLE_P(object); EG(objects_store).object_buckets[handle].bucket.obj.refcount++; + EG(objects_store).object_buckets[handle].bucket.obj.color = GC_BLACK; #if ZEND_DEBUG_OBJECTS fprintf(stderr, "Increased refcount of object id #%d\n", handle); #endif @@ -151,6 +156,7 @@ ZEND_API void zend_objects_store_add_ref ZEND_API void zend_objects_store_add_ref_by_handle(zend_object_handle handle TSRMLS_DC) { EG(objects_store).object_buckets[handle].bucket.obj.refcount++; + EG(objects_store).object_buckets[handle].bucket.obj.color = GC_BLACK; } #define ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST() \ @@ -167,6 +173,8 @@ ZEND_API void zend_objects_store_del_ref Z_ADDREF_P(zobject); zend_objects_store_del_ref_by_handle(handle TSRMLS_CC); Z_DELREF_P(zobject); + + CHECK_POSSIBLE_OBJECT_ROOT(handle); } /* @@ -201,6 +209,7 @@ ZEND_API void zend_objects_store_del_ref } } if (obj->refcount == 1) { + REMOVE_ZEND_OBJECT_FROM_BUFFER(obj); if (obj->free_storage) { zend_try { obj->free_storage(obj->object TSRMLS_CC); Index: Zend/zend_objects_API.h =================================================================== RCS file: /repository/ZendEngine2/zend_objects_API.h,v retrieving revision 1.20.2.1.2.4 diff -u -p -d -r1.20.2.1.2.4 zend_objects_API.h --- Zend/zend_objects_API.h 21 Jul 2007 00:35:14 -0000 1.20.2.1.2.4 +++ Zend/zend_objects_API.h 8 Oct 2007 04:33:11 -0000 @@ -38,6 +38,8 @@ typedef struct _zend_object_store_bucket zend_objects_free_object_storage_t free_storage; zend_objects_store_clone_t clone; zend_uint refcount; + zend_ushort buffered; + zend_uchar color; } obj; struct { int next; Index: Zend/zend_variables.c =================================================================== RCS file: /repository/ZendEngine2/zend_variables.c,v retrieving revision 1.62.2.1.2.2.2.2 diff -u -p -d -r1.62.2.1.2.2.2.2 zend_variables.c --- Zend/zend_variables.c 7 Oct 2007 05:22:03 -0000 1.62.2.1.2.2.2.2 +++ Zend/zend_variables.c 8 Oct 2007 04:33:11 -0000 @@ -40,8 +40,11 @@ ZEND_API void _zval_dtor_func(zval *zval TSRMLS_FETCH(); if (zvalue->value.ht && (zvalue->value.ht != &EG(symbol_table))) { - zend_hash_destroy(zvalue->value.ht); - FREE_HASHTABLE(zvalue->value.ht); + if (GC_G(gc_active) == 0) + zend_hash_destroy(Z_ARRVAL_P(zvalue)); + else + zend_hash_destroy_no_destructor(Z_ARRVAL_P(zvalue)); + FREE_HASHTABLE(Z_ARRVAL_P(zvalue)); } } break; Index: Zend/zend_vm_def.h =================================================================== RCS file: /repository/ZendEngine2/zend_vm_def.h,v retrieving revision 1.59.2.29.2.48.2.13 diff -u -p -d -r1.59.2.29.2.48.2.13 zend_vm_def.h --- Zend/zend_vm_def.h 7 Oct 2007 05:22:03 -0000 1.59.2.29.2.48.2.13 +++ Zend/zend_vm_def.h 8 Oct 2007 04:33:11 -0000 @@ -2781,6 +2781,7 @@ ZEND_VM_HANDLER(71, ZEND_INIT_ARRAY, CON zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (OP1_TYPE == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if !defined(ZEND_VM_SPEC) || OP1_TYPE != IS_UNUSED Index: Zend/zend_vm_execute.h =================================================================== RCS file: /repository/ZendEngine2/zend_vm_execute.h,v retrieving revision 1.62.2.30.2.49.2.12 diff -u -p -d -r1.62.2.30.2.49.2.12 zend_vm_execute.h --- Zend/zend_vm_execute.h 7 Oct 2007 05:22:03 -0000 1.62.2.30.2.49.2.12 +++ Zend/zend_vm_execute.h 8 Oct 2007 04:33:14 -0000 @@ -2663,6 +2663,7 @@ static int ZEND_INIT_ARRAY_SPEC_CONST_CO zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_CONST == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CONST != IS_UNUSED @@ -3145,6 +3146,7 @@ static int ZEND_INIT_ARRAY_SPEC_CONST_TM zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_CONST == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CONST != IS_UNUSED @@ -3593,6 +3595,7 @@ static int ZEND_INIT_ARRAY_SPEC_CONST_VA zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_CONST == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CONST != IS_UNUSED @@ -3775,6 +3778,7 @@ static int ZEND_INIT_ARRAY_SPEC_CONST_UN zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_CONST == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CONST != IS_UNUSED @@ -4222,6 +4226,7 @@ static int ZEND_INIT_ARRAY_SPEC_CONST_CV zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_CONST == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CONST != IS_UNUSED @@ -5685,6 +5690,7 @@ static int ZEND_INIT_ARRAY_SPEC_TMP_CONS zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_TMP_VAR == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_TMP_VAR != IS_UNUSED @@ -6132,6 +6138,7 @@ static int ZEND_INIT_ARRAY_SPEC_TMP_TMP_ zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_TMP_VAR == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_TMP_VAR != IS_UNUSED @@ -6579,6 +6586,7 @@ static int ZEND_INIT_ARRAY_SPEC_TMP_VAR_ zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_TMP_VAR == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_TMP_VAR != IS_UNUSED @@ -6672,6 +6680,7 @@ static int ZEND_INIT_ARRAY_SPEC_TMP_UNUS zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_TMP_VAR == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_TMP_VAR != IS_UNUSED @@ -7116,6 +7125,7 @@ static int ZEND_INIT_ARRAY_SPEC_TMP_CV_H zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_TMP_VAR == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_TMP_VAR != IS_UNUSED @@ -9889,6 +9899,7 @@ static int ZEND_INIT_ARRAY_SPEC_VAR_CONS zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_VAR == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_VAR != IS_UNUSED @@ -11468,6 +11479,7 @@ static int ZEND_INIT_ARRAY_SPEC_VAR_TMP_ zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_VAR == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_VAR != IS_UNUSED @@ -13085,6 +13097,7 @@ static int ZEND_INIT_ARRAY_SPEC_VAR_VAR_ zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_VAR == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_VAR != IS_UNUSED @@ -13871,6 +13884,7 @@ static int ZEND_INIT_ARRAY_SPEC_VAR_UNUS zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_VAR == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_VAR != IS_UNUSED @@ -15220,6 +15234,7 @@ static int ZEND_INIT_ARRAY_SPEC_VAR_CV_H zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_VAR == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_VAR != IS_UNUSED @@ -16336,6 +16351,7 @@ static int ZEND_INIT_ARRAY_SPEC_UNUSED_C zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_UNUSED == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_UNUSED != IS_UNUSED @@ -17302,6 +17318,7 @@ static int ZEND_INIT_ARRAY_SPEC_UNUSED_T zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_UNUSED == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_UNUSED != IS_UNUSED @@ -18268,6 +18285,7 @@ static int ZEND_INIT_ARRAY_SPEC_UNUSED_V zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_UNUSED == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_UNUSED != IS_UNUSED @@ -18792,6 +18810,7 @@ static int ZEND_INIT_ARRAY_SPEC_UNUSED_U zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_UNUSED == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_UNUSED != IS_UNUSED @@ -19498,6 +19517,7 @@ static int ZEND_INIT_ARRAY_SPEC_UNUSED_C zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_UNUSED == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_UNUSED != IS_UNUSED @@ -22203,6 +22223,7 @@ static int ZEND_INIT_ARRAY_SPEC_CV_CONST zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_CV == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CV != IS_UNUSED @@ -23685,6 +23706,7 @@ static int ZEND_INIT_ARRAY_SPEC_CV_TMP_H zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_CV == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CV != IS_UNUSED @@ -25204,6 +25226,7 @@ static int ZEND_INIT_ARRAY_SPEC_CV_VAR_H zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_CV == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CV != IS_UNUSED @@ -25896,6 +25919,7 @@ static int ZEND_INIT_ARRAY_SPEC_CV_UNUSE zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_CV == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CV != IS_UNUSED @@ -27151,6 +27175,7 @@ static int ZEND_INIT_ARRAY_SPEC_CV_CV_HA zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); + INIT_GC(&EX_T(opline->result.u.var).tmp_var); if (IS_CV == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CV != IS_UNUSED Index: main/main.c =================================================================== RCS file: /repository/php-src/main/main.c,v retrieving revision 1.640.2.23.2.57.2.2 diff -u -p -d -r1.640.2.23.2.57.2.2 main.c --- main/main.c 1 Oct 2007 14:51:11 -0000 1.640.2.23.2.57.2.2 +++ main/main.c 8 Oct 2007 04:33:17 -0000 @@ -1700,6 +1700,8 @@ int php_module_startup(sapi_module_struc 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; @@ -1749,6 +1751,10 @@ int php_module_startup(sapi_module_struc /* Register Zend ini entries */ zend_register_standard_ini_entries(TSRMLS_C); + if (UNEXPECTED(GC_G(gc_enabled))) { + gc_root_buffer_ctor(TSRMLS_C); + } + /* Disable realpath cache if safe_mode or open_basedir are set */ if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) { CWDG(realpath_cache_size_limit) = 0; @@ -1901,6 +1907,7 @@ void php_module_shutdown(TSRMLS_D) zend_ini_shutdown(TSRMLS_C); shutdown_memory_manager(CG(unclean_shutdown), 1 TSRMLS_CC); core_globals_dtor(&core_globals TSRMLS_CC); + gc_globals_dtor(TSRMLS_C); #else zend_ini_global_shutdown(TSRMLS_C); ts_free_id(core_globals_id);