From 73b159e0567683f96a2da78d7a2e60cf0f6f0bbc Mon Sep 17 00:00:00 2001 From: Andi Gutmans Date: Thu, 27 Dec 2001 14:35:09 +0000 Subject: [PATCH] - Experimental support for destructors. We need to see if destructors - will actually work well in the context of PHP so we should consider this - as experimental. Possible problems might be that when the constructor is - run PHP might not be in a stable state. --- Zend/zend.c | 1 + Zend/zend.h | 1 + Zend/zend_API.h | 2 ++ Zend/zend_compile.c | 7 ++++- Zend/zend_objects.c | 64 +++++++++++++++++++++++++++++++++++++++------ Zend/zend_objects.h | 1 + 6 files changed, 67 insertions(+), 9 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index ae58ac5f4b..cee2577ad9 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -257,6 +257,7 @@ static void register_standard_class(void) zend_hash_init_ex(&zend_standard_class_def.class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0); zend_hash_init_ex(&zend_standard_class_def.function_table, 0, NULL, ZEND_FUNCTION_DTOR, 1, 0); zend_standard_class_def.constructor = NULL; + zend_standard_class_def.destructor = NULL; zend_standard_class_def.clone = NULL; zend_standard_class_def.handle_function_call = NULL; zend_standard_class_def.handle_property_get = NULL; diff --git a/Zend/zend.h b/Zend/zend.h index 88c9214299..6b90652ef3 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -291,6 +291,7 @@ struct _zend_class_entry { zend_function_entry *builtin_functions; union _zend_function *constructor; + union _zend_function *destructor; union _zend_function *clone; /* handlers */ diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 8b16c26586..5ae94c5e8f 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -88,6 +88,7 @@ class_container.name_length = sizeof(class_name)-1; \ class_container.builtin_functions = functions; \ class_container.constructor = NULL; \ + class_container.destructor = NULL; \ class_container.clone = NULL; \ class_container.handle_function_call = NULL; \ class_container.handle_property_get = NULL; \ @@ -100,6 +101,7 @@ class_container.name_length = sizeof(class_name)-1; \ class_container.builtin_functions = functions; \ class_container.constructor = NULL; \ + class_container.destructor = NULL; \ class_container.clone = NULL; \ class_container.handle_function_call = handle_fcall; \ class_container.handle_property_get = handle_propget; \ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 54871f8251..4e45411edf 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -761,8 +761,10 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n zend_hash_update(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); if ((CG(active_class_entry)->name_length == (uint) name_len) && (!memcmp(CG(active_class_entry)->name, name, name_len))) { CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array); - } else if ((function_name->u.constant.value.str.len == sizeof("_construct")-1) && (!memcmp(function_name->u.constant.value.str.val, "_construct", sizeof("_clone")))) { + } else if ((function_name->u.constant.value.str.len == sizeof("_construct")-1) && (!memcmp(function_name->u.constant.value.str.val, "_construct", sizeof("_construct")))) { CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array); + } else if ((function_name->u.constant.value.str.len == sizeof("_destruct")-1) && (!memcmp(function_name->u.constant.value.str.val, "_destruct", sizeof("_destruct")))) { + CG(active_class_entry)->destructor = (zend_function *) CG(active_op_array); } else if ((function_name->u.constant.value.str.len == sizeof("_clone")-1) && (!memcmp(function_name->u.constant.value.str.val, "_clone", sizeof("_clone")))) { CG(active_class_entry)->clone = (zend_function *) CG(active_op_array); } @@ -1361,6 +1363,7 @@ static void create_class(HashTable *class_table, char *name, int name_length, ze zend_hash_init(&new_class_entry.constants_table, 10, NULL, ZVAL_PTR_DTOR, 0); new_class_entry.constructor = NULL; + new_class_entry.destructor = NULL; new_class_entry.clone = NULL; new_class_entry.handle_function_call = NULL; @@ -1849,6 +1852,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod zend_hash_init(&new_class_entry.constants_table, 10, NULL, ZVAL_PTR_DTOR, 0); new_class_entry.constructor = NULL; + new_class_entry.destructor = NULL; new_class_entry.clone = NULL; new_class_entry.handle_function_call = NULL; @@ -1879,6 +1883,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod zend_hash_copy(&new_class_entry.constants_table, &parent_class->constants_table, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); new_class_entry.constructor = parent_class->constructor; + new_class_entry.destructor = parent_class->destructor; /* FIXME: What do we do with clone? */ diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index f86148158d..776f7d9076 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -27,6 +27,43 @@ void zend_objects_destroy(zend_objects *objects) efree(objects->object_buckets); } +static inline void zend_objects_destroy_object(zend_object *object, zend_object_handle handle TSRMLS_DC) +{ + if (object->ce->destructor) { + zval *obj; + zval *destructor_func_name; + zval *retval_ptr; + HashTable symbol_table; + + MAKE_STD_ZVAL(obj); + obj->type = IS_OBJECT; + obj->value.obj.handle = handle; + obj->value.obj.handlers = &zoh; + zval_copy_ctor(obj); + + + /* FIXME: Optimize this so that we use the old_object->ce->destructor function pointer instead of the name */ + MAKE_STD_ZVAL(destructor_func_name); + destructor_func_name->type = IS_STRING; + destructor_func_name->value.str.val = estrndup("_destruct", sizeof("_destruct")-1); + destructor_func_name->value.str.len = sizeof("_destruct")-1; + + ZEND_INIT_SYMTABLE(&symbol_table); + + call_user_function_ex(NULL, &obj, destructor_func_name, &retval_ptr, 0, NULL, 0, &symbol_table TSRMLS_CC); + + zend_hash_destroy(&symbol_table); + zval_ptr_dtor(&obj); + zval_ptr_dtor(&destructor_func_name); + zval_ptr_dtor(&retval_ptr); + } + + /* Nuke the object */ + zend_hash_destroy(object->properties); + efree(object->properties); + +} + zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class_type) { zend_object_handle handle; @@ -45,6 +82,7 @@ zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class handle = EG(objects).top++; } EG(objects).object_buckets[handle].valid = 1; + EG(objects).object_buckets[handle].constructor_called = 0; EG(objects).object_buckets[handle].bucket.obj.refcount = 1; *object = &EG(objects).object_buckets[handle].bucket.obj.object; @@ -93,9 +131,14 @@ void zend_objects_delete_obj(zend_object_handle handle) } object = &EG(objects).object_buckets[handle].bucket.obj.object; - zend_hash_destroy(object->properties); - efree(object->properties); + + if (!EG(objects).object_buckets[handle].constructor_called) { + EG(objects).object_buckets[handle].constructor_called = 1; + zend_objects_destroy_object(object, handle TSRMLS_CC); + } + EG(objects).object_buckets[handle].valid = 0; + #if ZEND_DEBUG_OBJECTS fprintf(stderr, "Deleted object id #%d\n", handle); #endif @@ -110,13 +153,18 @@ void zend_objects_del_ref(zend_object_handle handle) zend_object *object; if (EG(objects).object_buckets[handle].valid) { - object = &EG(objects).object_buckets[handle].bucket.obj.object; - zend_hash_destroy(object->properties); - efree(object->properties); + if (!EG(objects).object_buckets[handle].constructor_called) { + object = &EG(objects).object_buckets[handle].bucket.obj.object; + EG(objects).object_buckets[handle].constructor_called = 1; + zend_objects_destroy_object(object, handle TSRMLS_CC); + } + } + /* FIXME: Optimizer this so that only if the constructor was called we recheck the refcount */ + if (EG(objects).object_buckets[handle].bucket.obj.refcount == 0) { + EG(objects).object_buckets[handle].bucket.free_list.next = EG(objects).free_list_head; + EG(objects).free_list_head = handle; + EG(objects).object_buckets[handle].valid = 0; } - EG(objects).object_buckets[handle].bucket.free_list.next = EG(objects).free_list_head; - EG(objects).free_list_head = handle; - EG(objects).object_buckets[handle].valid = 0; #if ZEND_DEBUG_OBJECTS fprintf(stderr, "Deallocated object id #%d\n", handle); #endif diff --git a/Zend/zend_objects.h b/Zend/zend_objects.h index 91e4d29276..b649163007 100644 --- a/Zend/zend_objects.h +++ b/Zend/zend_objects.h @@ -5,6 +5,7 @@ typedef struct _zend_object_bucket { zend_bool valid; + zend_bool constructor_called; union _bucket { struct { zend_object object; -- 2.40.0