]> granicus.if.org Git - php/commitdiff
- Sync Engine2 CVS with latest Engine CVS
authorAndi Gutmans <andi@php.net>
Tue, 7 Aug 2001 03:17:33 +0000 (03:17 +0000)
committerAndi Gutmans <andi@php.net>
Tue, 7 Aug 2001 03:17:33 +0000 (03:17 +0000)
14 files changed:
Zend/ZendTS.dsp
Zend/zend.h
Zend/zend_API.c
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_execute_API.c
Zend/zend_globals.h
Zend/zend_language_parser.y
Zend/zend_language_scanner.l
Zend/zend_objects.c [new file with mode: 0644]
Zend/zend_objects.h [new file with mode: 0644]
Zend/zend_operators.h
Zend/zend_variables.c

index 699601644d55efca4beb494bb8889dca4ff632b1..0929f815df3492e84046e930a8a739df241a4f78 100644 (file)
@@ -212,6 +212,10 @@ SOURCE=.\zend_llist.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\zend_objects.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\zend_opcode.c\r
 # End Source File\r
 # Begin Source File\r
@@ -352,6 +356,10 @@ SOURCE=.\zend_modules.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\zend_objects.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\zend_operators.h\r
 # End Source File\r
 # Begin Source File\r
index 5273a92b53ba6d051f63159df5f78207f81b6faf..090ae3c829bef0dd1375fb24a909f6f26eaf7d5b 100644 (file)
@@ -175,6 +175,29 @@ typedef struct _zend_object {
        HashTable *properties;
 } zend_object;
 
+typedef unsigned int zend_object_handle;
+
+typedef zend_object *(*get_address_t)(zend_object_handle handle); /* Don't return zval ** so that we can't change it */
+typedef zval **(*get_property_address_t)(zend_object_handle handle, zval *offset, int type);
+typedef void (*add_ref_t)(zend_object_handle handle);
+typedef void (*del_ref_t)(zend_object_handle handle);
+typedef void (*delete_obj_t)(zend_object_handle handle);
+
+typedef struct _zend_object_handlers {
+       get_address_t get_address;
+       get_property_address_t get_property_address;
+       add_ref_t add_ref;
+       del_ref_t del_ref;
+       delete_obj_t delete_obj;
+} zend_object_handlers;
+
+typedef        struct _zend_object_value {
+       zend_object_handle handle;
+       zend_object_handlers handlers;
+} zend_object_value;
+
+#include "zend_objects.h"
+
 typedef union _zvalue_value {
        long lval;                                      /* long value */
        double dval;                            /* double value */
@@ -183,7 +206,12 @@ typedef union _zvalue_value {
                int len;
        } str;
        HashTable *ht;                          /* hash table value */
-       zend_object obj;
+/*     struct {
+               zend_class_entry *ce;
+               HashTable *properties;
+       } obj;
+*/
+       zend_object_value obj;
 } zvalue_value;
 
 
index 08aaeeb528753fea9a47e2c9ef8703dfa7311ff6..1cf03a147cb82c8ca0c40bd77db416187d022029 100644 (file)
@@ -211,7 +211,6 @@ static int zend_check_class(zval *obj, zend_class_entry *expected_ce)
                        return 1;
                }
        }
-
        return 0;
 }
 
@@ -569,17 +568,21 @@ ZEND_API int _array_init(zval *arg ZEND_FILE_LINE_DC)
 ZEND_API int _object_init_ex(zval *arg, zend_class_entry *class_type ZEND_FILE_LINE_DC TSRMLS_DC)
 {
        zval *tmp;
+       zend_object *object;
 
        if (!class_type->constants_updated) {
                zend_hash_apply_with_argument(&class_type->default_properties, (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC);
                class_type->constants_updated = 1;
        }
        
-       ALLOC_HASHTABLE_REL(arg->value.obj.properties);
-       zend_hash_init(arg->value.obj.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
-       zend_hash_copy(arg->value.obj.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+       arg->value.obj = zend_objects_new(&object);
+
+       ALLOC_HASHTABLE_REL(object->properties);
+       zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+       zend_hash_copy(object->properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+       object->ce = class_type;
+
        arg->type = IS_OBJECT;
-       arg->value.obj.ce = class_type;
        return SUCCESS;
 }
 
@@ -943,7 +946,7 @@ ZEND_API int add_property_resource_ex(zval *arg, char *key, uint key_len, long n
        
        MAKE_STD_ZVAL(tmp);
        ZVAL_RESOURCE(tmp, n);
-       
+
        return zend_hash_update(Z_OBJPROP_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL);
 }
 
@@ -954,7 +957,7 @@ ZEND_API int add_property_double_ex(zval *arg, char *key, uint key_len, double d
        
        MAKE_STD_ZVAL(tmp);
        ZVAL_DOUBLE(tmp, d);
-       
+
        return zend_hash_update(Z_OBJPROP_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL);
 }
 
index 5422bff2ad5a29c728f35c4d3b48c3e9613c0d47..b34e6ff93a25c00fa293c2b203e772a7063862d3 100644 (file)
@@ -704,7 +704,6 @@ void zend_do_free(znode *op1 TSRMLS_DC)
        }               
 }
 
-
 void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference  TSRMLS_DC)
 {
        zend_op_array op_array;
@@ -2022,7 +2021,7 @@ void zend_do_indirect_references(znode *result, znode *num_references, znode *va
 }
 
 
-void zend_do_unset(znode *variable TSRMLS_DC)
+void zend_do_unset(znode *variable, int type TSRMLS_DC)
 {
        zend_op *last_op;
 
@@ -2038,6 +2037,7 @@ void zend_do_unset(znode *variable TSRMLS_DC)
                        break;
 
        }
+       last_op->extended_value = type;
 }
 
 
index fda7b57239deccd44c866f20eeff6efa5a3ead1f..3fd85e527a4a920930d227de8e9586852182c4ec 100644 (file)
@@ -329,7 +329,7 @@ void zend_do_new_list_end(TSRMLS_D);
 void zend_do_cast(znode *result, znode *expr, int type TSRMLS_DC);
 void zend_do_include_or_eval(int type, znode *result, znode *op1 TSRMLS_DC);
 
-void zend_do_unset(znode *variable TSRMLS_DC);
+void zend_do_unset(znode *variable, int type TSRMLS_DC);
 void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC);
 
 void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_token, znode *as_token, int variable TSRMLS_DC);
@@ -537,6 +537,10 @@ int zendlex(znode *zendlval TSRMLS_DC);
 #define ZEND_FETCH_LOCAL       1
 #define ZEND_FETCH_STATIC      2
 
+/* unset types */
+#define ZEND_UNSET_REG 0
+#define ZEND_UNSET_OBJ 1
+
 /* var status for backpatching */
 #define BP_VAR_R                       0
 #define BP_VAR_W                       1
index ec82e104a882f4189e3b179c2769fac88d4eb025..ba96d242be3bd9c53d4b16efdb3fec3590f17a21 100644 (file)
@@ -1497,7 +1497,7 @@ binary_assign_op_addr: {
                                                        object.ptr = _get_object_zval_ptr(&opline->op1, Ts, &EG(free_op1) TSRMLS_CC);
                                                        
                                                        if ((!object.ptr && Ts[opline->op1.u.var].EA.type==IS_OVERLOADED_OBJECT)                                                                
-                                                               || ((object.ptr && object.ptr->type==IS_OBJECT) && (object.ptr->value.obj.ce->handle_function_call))) { /* overloaded function call */
+                                                               || ((object.ptr && object.ptr->type==IS_OBJECT) && Z_OBJCE_P(object.ptr)->handle_function_call)) { /* overloaded function call */
                                                                zend_overloaded_element overloaded_element;
 
                                                                overloaded_element.element = *function_name;
@@ -1517,15 +1517,22 @@ binary_assign_op_addr: {
                                                                goto overloaded_function_call_cont;
                                                        }
 
-                                                       if (!object.ptr || object.ptr->type != IS_OBJECT) {
+                                                       if (object.ptr && object.ptr->type == IS_OBJECT) {
+                                                               active_function_table = &Z_OBJCE_P(object.ptr)->function_table; 
+                                                       } else {
                                                                zend_error(E_ERROR, "Call to a member function on a non-object");
                                                        }
-                                                       if (!object.ptr->is_ref && object.ptr->refcount > 1) {
-                                                               zend_error(E_ERROR, "Bug: Problem in method call\n");
+                                                       if (!PZVAL_IS_REF(object.ptr)) {
+                                                               object.ptr->refcount++; /* For $this pointer */
+                                                       } else {
+                                                               zval *this_ptr;
+                                                               ALLOC_ZVAL(this_ptr);
+                                                               *this_ptr = *object.ptr;
+                                                               INIT_PZVAL(this_ptr);
+                                                               zval_copy_ctor(this_ptr);
+                                                               object.ptr = this_ptr;
                                                        }
-                                                       object.ptr->is_ref=1;
-                                                       object.ptr->refcount++; /* For $this pointer */
-                                                       active_function_table = &(object.ptr->value.obj.ce->function_table);
+                                                       active_function_table = &Z_OBJCE_P(object.ptr)->function_table;
                                                }
                                        } else { /* function pointer */
                                                object.ptr = NULL;
@@ -1568,7 +1575,7 @@ do_fcall_common:
                                                INIT_ZVAL(*(Ts[opline->result.u.var].var.ptr));
                                                ((zend_internal_function *) function_state.function)->handler(opline->extended_value, Ts[opline->result.u.var].var.ptr, object.ptr, return_value_used TSRMLS_CC);
                                                if (object.ptr) {
-                                                       object.ptr->refcount--;
+                                                       zval_ptr_dtor(&object.ptr);
                                                }
                                                Ts[opline->result.u.var].var.ptr->is_ref = 0;
                                                Ts[opline->result.u.var].var.ptr->refcount = 1;
@@ -1596,9 +1603,6 @@ do_fcall_common:
                                                        zval *null_ptr = NULL;
 
                                                        zend_hash_update(function_state.function_symbol_table, "this", sizeof("this"), &null_ptr, sizeof(zval *), (void **) &this_ptr);
-                                                       if (!PZVAL_IS_REF(object.ptr)) {
-                                                               zend_error(E_WARNING, "Problem with method call - please report this bug");
-                                       }
                                                        *this_ptr = object.ptr;
                                                        object.ptr = NULL;
                                                }
@@ -2142,6 +2146,8 @@ send_by_ref:
                                NEXT_OPCODE();
                        case ZEND_UNSET_VAR: {
                                        zval tmp, *variable = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R);
+                                       zval **object;
+                                       zend_bool unset_object;
 
                                        if (variable->type != IS_STRING) {
                                                tmp = *variable;
@@ -2150,6 +2156,18 @@ send_by_ref:
                                                variable = &tmp;
                                        }
 
+                                       unset_object = (opline->extended_value == ZEND_UNSET_OBJ);
+                                       
+                                       if (unset_object) {
+                                               if (zend_hash_find(EG(active_symbol_table), variable->value.str.val, variable->value.str.len+1, (void **)&object) == FAILURE) {
+                                                       zend_error(E_ERROR, "Cannot delete non-existing object");
+                                               }
+                                               if (Z_TYPE_PP(object) != IS_OBJECT) {
+                                                       zend_error(E_ERROR, "Cannot call delete on non-object type");
+                                               }
+                                               (*object)->value.obj.handlers.delete_obj((*object)->value.obj.handle);
+                                       }
+
                                        zend_hash_del(EG(active_symbol_table), variable->value.str.val, variable->value.str.len+1);
 
                                        if (variable == &tmp) {
@@ -2161,7 +2179,11 @@ send_by_ref:
                        case ZEND_UNSET_DIM_OBJ: {
                                        zval **container = get_zval_ptr_ptr(&opline->op1, Ts, BP_VAR_R);
                                        zval *offset = get_zval_ptr(&opline->op2, Ts, &EG(free_op2), BP_VAR_R);
+                                       zend_bool unset_object;
+                                       zval **object;
 
+                                       unset_object = (opline->extended_value == ZEND_UNSET_OBJ);
+                                       
                                        if (container) {
                                                HashTable *ht;
 
@@ -2170,7 +2192,7 @@ send_by_ref:
                                                                ht = (*container)->value.ht;
                                                                break;
                                                        case IS_OBJECT:
-                                                               ht = (*container)->value.obj.properties;
+                                                               ht = Z_OBJPROP_PP(container);
                                                                break;
                                                        default:
                                                                ht = NULL;
@@ -2190,13 +2212,44 @@ send_by_ref:
                                                                                } else {
                                                                                        index = offset->value.lval;
                                                                                }
+
+                                                                               if (unset_object) {
+                                                                                       if (zend_hash_index_find(ht, index, (void **)&object) == FAILURE) {
+                                                                                               zend_error(E_ERROR, "Cannot delete non-existing object");
+                                                                                       }
+                                                                                       if (Z_TYPE_PP(object) != IS_OBJECT) {
+                                                                                               zend_error(E_ERROR, "Cannot call delete on non-object type");
+                                                                                       }
+                                                                                       (*object)->value.obj.handlers.delete_obj((*object)->value.obj.handle);
+                                                                               }
+                                       
                                                                                zend_hash_index_del(ht, index);
                                                                                break;
                                                                        }
                                                                case IS_STRING:
+                                                                       if (unset_object) {
+                                                                               if (zend_hash_find(ht, offset->value.str.val, offset->value.str.len+1, (void **)&object) == FAILURE) {
+                                                                                       zend_error(E_ERROR, "Cannot delete non-existing object");
+                                                                               }
+                                                                               if (Z_TYPE_PP(object) != IS_OBJECT) {
+                                                                                       zend_error(E_ERROR, "Cannot call delete on non-object type");
+                                                                               }
+                                                                               (*object)->value.obj.handlers.delete_obj((*object)->value.obj.handle);
+                                                                       }
+
                                                                        zend_hash_del(ht, offset->value.str.val, offset->value.str.len+1);
                                                                        break;
                                                                case IS_NULL:
+                                                                       if (unset_object) {
+                                                                               if (zend_hash_find(ht, "", sizeof(""), (void **)&object) == FAILURE) {
+                                                                                       zend_error(E_ERROR, "Cannot delete non-existing object");
+                                                                               }
+                                                                               if (Z_TYPE_PP(object) != IS_OBJECT) {
+                                                                                       zend_error(E_ERROR, "Cannot call delete on non-object type");
+                                                                               }
+                                                                               (*object)->value.obj.handlers.delete_obj((*object)->value.obj.handle);
+                                                                       }
+
                                                                        zend_hash_del(ht, "", sizeof(""));
                                                                        break;
                                                                default: 
@@ -2259,7 +2312,6 @@ send_by_ref:
                                        PZVAL_LOCK(array);
 
                                        fe_ht = HASH_OF(array);
-
                                        if (!fe_ht) {
                                                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
                                                opline = op_array->opcodes+opline->op2.u.opline_num;
@@ -2293,15 +2345,18 @@ send_by_ref:
                                }
                                NEXT_OPCODE();
                        case ZEND_JMP_NO_CTOR: {
-                                       zval *object;
+                                       zval *object_zval;
+                                       zend_object *object;
 
                                        if (opline->op1.op_type == IS_VAR) {
                                                PZVAL_LOCK(*Ts[opline->op1.u.var].var.ptr_ptr);
                                        }
                                        
-                                       object = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R);
-                                       if (!object->value.obj.ce->handle_function_call
-                                               && !zend_hash_exists(&object->value.obj.ce->function_table, object->value.obj.ce->name, object->value.obj.ce->name_length+1)) {
+                                       object_zval = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R);
+                                       object = object_zval->value.obj.handlers.get_address(object_zval->value.obj.handle);
+
+                                       if (!object->ce->handle_function_call
+                                               && !zend_hash_exists(&object->ce->function_table, object->ce->name, object->ce->name_length+1)) {
                                                opline = op_array->opcodes + opline->op2.u.opline_num;
                                                continue;
                                        }
index 1c9e42a5e41699166694468e9d031128fa82e586..971d00fe0b93798753a5b79035b2d8b780cdd630 100644 (file)
@@ -151,7 +151,7 @@ void init_executor(TSRMLS_D)
        zend_ptr_stack_init(&EG(user_error_handlers));
 
        EG(orig_error_reporting) = EG(error_reporting);
-
+       zend_objects_init(&EG(objects), 1024);
 #ifdef ZEND_WIN32
        EG(timed_out) = 0;
 #endif
@@ -207,6 +207,7 @@ void shutdown_executor(TSRMLS_D)
                zend_ptr_stack_destroy(&EG(user_error_handlers));
 
                EG(error_reporting) = EG(orig_error_reporting);
+               zend_objects_destroy(&EG(objects));
        } zend_end_try();
 }
 
@@ -268,7 +269,7 @@ ZEND_API void _zval_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC)
        if ((*zval_ptr)->refcount==0) {
                zval_dtor(*zval_ptr);
                safe_free_zval_ptr(*zval_ptr);
-       } else if (((*zval_ptr)->refcount == 1) && ((*zval_ptr)->type != IS_OBJECT)) {
+       } else if ((*zval_ptr)->refcount == 1) {
                (*zval_ptr)->is_ref = 0;
        }
 }
@@ -411,7 +412,7 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun
        }
        if (object_pp) {
                if (Z_TYPE_PP(object_pp) == IS_OBJECT) {
-                       function_table = &(*object_pp)->value.obj.ce->function_table;
+                       function_table = &Z_OBJCE_PP(object_pp)->function_table;
                } else if (Z_TYPE_PP(object_pp) == IS_STRING) {
                        zend_class_entry *ce;
                        char *lc_class;
index 65aa6eda747f58ab7199d3ae19fc44a176220e25..2e649d0eca0ae1607be878adb4b14f33f3339f9d 100644 (file)
@@ -200,6 +200,7 @@ struct _zend_executor_globals {
        int lambda_count;
 
        HashTable ini_directives;
+       zend_objects objects;
 
        void *reserved[ZEND_MAX_RESERVED_RESOURCES];
 };
index 46cce268a828ef13107f2d9e71a337209e8f6c87..d5ea4d14f02e252ea84d37616814863f76dbbdf5 100644 (file)
@@ -67,7 +67,7 @@
 %left '*' '/' '%'
 %right '!' '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@'
 %right '['
-%nonassoc T_NEW
+%nonassoc T_NEW T_DELETE
 %token T_EXIT
 %token T_IF
 %left T_ELSEIF
@@ -201,6 +201,7 @@ unticked_statement:
        |       T_FOREACH '(' expr_without_variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 0 TSRMLS_CC); } w_cvar foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); }
        |       T_DECLARE { zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(TSRMLS_C); }
        |       ';'             /* empty statement */
+       |       T_DELETE cvar   ';' { zend_do_end_variable_parse(BP_VAR_UNSET, 0 TSRMLS_CC); zend_do_unset(&$1, ZEND_UNSET_OBJ TSRMLS_CC); }
 ;
 
 unset_variables:
@@ -209,7 +210,7 @@ unset_variables:
 ;
 
 unset_variable:
-               cvar    { zend_do_end_variable_parse(BP_VAR_UNSET, 0 TSRMLS_CC); zend_do_unset(&$1 TSRMLS_CC); }
+               cvar    { zend_do_end_variable_parse(BP_VAR_UNSET, 0 TSRMLS_CC); zend_do_unset(&$1, ZEND_UNSET_REG TSRMLS_CC); }
 ;
 
 use_filename:
index f5f79e7ae4a6a402586ea1a03b61a377c1083e03..f1bd0393b695bbab36b7aabe7bf26d64593c2fa2 100644 (file)
@@ -765,6 +765,10 @@ NEWLINE ("\r"|"\n"|"\r\n")
        return T_NEW;
 }
 
+<ST_IN_SCRIPTING>"delete" {
+       return T_DELETE;
+}
+
 <ST_IN_SCRIPTING>"var" {
        return T_VAR;
 }
diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c
new file mode 100644 (file)
index 0000000..2380f77
--- /dev/null
@@ -0,0 +1,122 @@
+#include "zend.h"
+#include "zend_globals.h"
+
+#define ZEND_DEBUG_OBJECTS 0
+
+static zend_object_handlers zoh = {
+       zend_objects_get_address,
+       NULL,
+       zend_objects_add_ref,
+       zend_objects_del_ref,
+       zend_objects_delete_obj
+};
+
+void zend_objects_init(zend_objects *objects, zend_uint init_size)
+{
+       objects->object_buckets = (zend_object_bucket *) emalloc(init_size * sizeof(zend_object_bucket));
+       objects->top = 1; /* Skip 0 so that handles are true */
+       objects->size = init_size;
+       objects->free_list_head = -1;
+}
+
+void zend_objects_destroy(zend_objects *objects)
+{
+       efree(objects->object_buckets);
+}
+
+zend_object_value zend_objects_new(zend_object **object)
+{
+       TSRMLS_FETCH();
+
+       zend_object_handle handle;
+       zend_object_value retval;
+
+       if (EG(objects).free_list_head != -1) {
+               handle = EG(objects).free_list_head;
+               EG(objects).free_list_head = EG(objects).object_buckets[handle].bucket.free_list.next;
+       } else {
+               if (EG(objects).top == EG(objects).size) {
+                       EG(objects).size <<= 1;
+                       EG(objects).object_buckets = (zend_object_bucket *) erealloc(EG(objects).object_buckets, EG(objects).size * sizeof(zend_object_bucket));
+               }
+               handle = EG(objects).top++;
+       }
+       EG(objects).object_buckets[handle].valid = 1;
+       EG(objects).object_buckets[handle].bucket.obj.refcount = 1;
+       *object = &EG(objects).object_buckets[handle].bucket.obj.object;
+       retval.handle = handle;
+       retval.handlers = zoh;
+#if ZEND_DEBUG_OBJECTS
+       fprintf(stderr, "Allocated object id #%d\n", handle);
+#endif
+       return retval;
+}
+
+zend_object *zend_objects_get_address(zend_object_handle handle)
+{
+       TSRMLS_FETCH();
+
+       if (!EG(objects).object_buckets[handle].valid) {
+               zend_error(E_ERROR, "Trying to access invalid object");
+       }
+       return &EG(objects).object_buckets[handle].bucket.obj.object;
+}
+
+void zend_objects_add_ref(zend_object_handle handle)
+{
+       TSRMLS_FETCH();
+
+       if (!EG(objects).object_buckets[handle].valid) {
+               zend_error(E_ERROR, "Trying to add reference to invalid object");
+       }
+
+       EG(objects).object_buckets[handle].bucket.obj.refcount++;
+#if ZEND_DEBUG_OBJECTS
+       fprintf(stderr, "Increased refcount of object id #%d\n", handle);
+#endif
+}
+
+void zend_objects_delete_obj(zend_object_handle handle)
+{
+       zend_object *object;
+       TSRMLS_FETCH();
+
+       if (!EG(objects).object_buckets[handle].valid) {
+               zend_error(E_ERROR, "Trying to delete invalid object");
+       }
+
+       object = &EG(objects).object_buckets[handle].bucket.obj.object;
+       zend_hash_destroy(object->properties);
+       efree(object->properties);
+       EG(objects).object_buckets[handle].valid = 0;
+#if ZEND_DEBUG_OBJECTS
+       fprintf(stderr, "Deleted object id #%d\n", handle);
+#endif
+
+}
+
+void zend_objects_del_ref(zend_object_handle handle)
+{
+       TSRMLS_FETCH();
+
+       if (--EG(objects).object_buckets[handle].bucket.obj.refcount == 0) {
+               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);
+               }
+               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
+       }
+#if ZEND_DEBUG_OBJECTS
+       else {
+               fprintf(stderr, "Decreased refcount of object id #%d\n", handle);
+       }
+#endif
+}
diff --git a/Zend/zend_objects.h b/Zend/zend_objects.h
new file mode 100644 (file)
index 0000000..30660a6
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef ZEND_OBJECTS_H
+#define ZEND_OBJECTS_H
+
+#include "zend.h"
+
+typedef struct _zend_object_bucket {
+       zend_bool valid;
+       union _bucket {
+               struct {
+                       zend_object object;
+                       zend_uint refcount;
+               } obj;
+               struct {
+                       int next;
+               } free_list;
+       } bucket;
+} zend_object_bucket;
+
+typedef struct _zend_objects {
+       zend_object_bucket *object_buckets;
+       zend_uint top;
+       zend_uint size;
+       int free_list_head;
+} zend_objects;
+
+void zend_objects_init(zend_objects *objects, zend_uint init_size);
+void zend_objects_destroy(zend_objects *objects);
+zend_object_value zend_objects_new(zend_object **object);
+zend_object *zend_objects_get_address(zend_object_handle handle);
+void zend_objects_add_ref(zend_object_handle handle);
+void zend_objects_del_ref(zend_object_handle handle);
+void zend_objects_delete_obj(zend_object_handle handle);
+
+#endif /* ZEND_OBJECTS_H */
\ No newline at end of file
index 6df74c790c65b2aba0164fe8c6df855cd9ea42de..b1e2a4410e09789a589c74038a487198e8cac21b 100644 (file)
@@ -210,16 +210,15 @@ ZEND_API int zend_atoi(const char *str, int str_len);
        }
 
 
-
 #define Z_LVAL(zval)           (zval).value.lval
 #define Z_BVAL(zval)           ((zend_bool)(zval).value.lval)
 #define Z_DVAL(zval)           (zval).value.dval
 #define Z_STRVAL(zval)         (zval).value.str.val
 #define Z_STRLEN(zval)         (zval).value.str.len
 #define Z_ARRVAL(zval)         (zval).value.ht
-#define Z_OBJ(zval)                    &(zval).value.obj
-#define Z_OBJPROP(zval)                (zval).value.obj.properties
-#define Z_OBJCE(zval)          (zval).value.obj.ce
+#define Z_OBJ(zval)                    (zval).value.obj.handlers.get_address((zval).value.obj.handle)
+#define Z_OBJPROP(zval)                Z_OBJ(zval)->properties
+#define Z_OBJCE(zval)          Z_OBJ(zval)->ce
 #define Z_RESVAL(zval)         (zval).value.lval
 
 #define Z_LVAL_P(zval_p)               Z_LVAL(*zval_p)
index 5cb2ab5d6056ca6b9fcbb1e95d78739ce22c5229..757019860c9d115427117427c33b19bc7030364e 100644 (file)
@@ -54,8 +54,7 @@ ZEND_API void _zval_dtor(zval *zvalue ZEND_FILE_LINE_DC)
                        }
                        break;
                case IS_OBJECT:
-                       zend_hash_destroy(zvalue->value.obj.properties);
-                       FREE_HASHTABLE(zvalue->value.obj.properties);
+                       zvalue->value.obj.handlers.del_ref(zvalue->value.obj.handle);
                        break;
                case IS_RESOURCE:       {
                                TSRMLS_FETCH();
@@ -119,14 +118,8 @@ ZEND_API int _zval_copy_ctor(zval *zvalue ZEND_FILE_LINE_DC)
                                zend_hash_copy(zvalue->value.ht, original_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
                        }
                        break;
-               case IS_OBJECT: {
-                               zval *tmp;
-                               HashTable *original_ht = zvalue->value.obj.properties;
-
-                               ALLOC_HASHTABLE_REL(zvalue->value.obj.properties);
-                               zend_hash_init(zvalue->value.obj.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
-                               zend_hash_copy(zvalue->value.obj.properties, original_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
-                       }
+               case IS_OBJECT:
+                       zvalue->value.obj.handlers.add_ref(zvalue->value.obj.handle);
                        break;
        }
        return SUCCESS;