You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 lines
7.5 KiB

25 years ago
  1. #include "zend.h"
  2. #include "zend_globals.h"
  3. #include "zend_variables.h"
  4. #include "zend_API.h"
  5. #define ZEND_DEBUG_OBJECTS 0
  6. void zend_objects_init(zend_objects *objects, zend_uint init_size)
  7. {
  8. objects->object_buckets = (zend_object_bucket *) emalloc(init_size * sizeof(zend_object_bucket));
  9. objects->top = 1; /* Skip 0 so that handles are true */
  10. objects->size = init_size;
  11. objects->free_list_head = -1;
  12. }
  13. void zend_objects_destroy(zend_objects *objects)
  14. {
  15. efree(objects->object_buckets);
  16. }
  17. static inline void zend_objects_call_destructor(zend_object *object, zend_object_handle handle TSRMLS_DC)
  18. {
  19. if (object->ce->destructor) {
  20. zval *obj;
  21. zval *destructor_func_name;
  22. zval *retval_ptr;
  23. HashTable symbol_table;
  24. MAKE_STD_ZVAL(obj);
  25. obj->type = IS_OBJECT;
  26. obj->value.obj.handle = handle;
  27. obj->value.obj.handlers = &std_object_handlers;
  28. zval_copy_ctor(obj);
  29. /* FIXME: Optimize this so that we use the old_object->ce->destructor function pointer instead of the name */
  30. MAKE_STD_ZVAL(destructor_func_name);
  31. destructor_func_name->type = IS_STRING;
  32. destructor_func_name->value.str.val = estrndup("__destruct", sizeof("__destruct")-1);
  33. destructor_func_name->value.str.len = sizeof("__destruct")-1;
  34. ZEND_INIT_SYMTABLE(&symbol_table);
  35. call_user_function_ex(NULL, &obj, destructor_func_name, &retval_ptr, 0, NULL, 0, &symbol_table TSRMLS_CC);
  36. zend_hash_destroy(&symbol_table);
  37. zval_ptr_dtor(&obj);
  38. zval_ptr_dtor(&destructor_func_name);
  39. if (retval_ptr) {
  40. zval_ptr_dtor(&retval_ptr);
  41. }
  42. }
  43. }
  44. static inline void zend_objects_destroy_object(zend_object *object, zend_object_handle handle TSRMLS_DC)
  45. {
  46. zend_objects_call_destructor(object, handle TSRMLS_CC);
  47. /* Nuke the object */
  48. zend_hash_destroy(object->properties);
  49. efree(object->properties);
  50. }
  51. void zend_objects_call_destructors(zend_objects *objects TSRMLS_DC)
  52. {
  53. zend_uint i = 1;
  54. for (i = 1; i < objects->top ; i++) {
  55. if (EG(objects).object_buckets[i].valid) {
  56. EG(objects).object_buckets[i].destructor_called = 1;
  57. zend_objects_destroy_object(&EG(objects).object_buckets[i].bucket.obj.object, i TSRMLS_CC);
  58. EG(objects).object_buckets[i].valid = 0;
  59. }
  60. }
  61. }
  62. zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class_type)
  63. {
  64. zend_object_handle handle;
  65. zend_object_value retval;
  66. TSRMLS_FETCH();
  67. if (EG(objects).free_list_head != -1) {
  68. handle = EG(objects).free_list_head;
  69. EG(objects).free_list_head = EG(objects).object_buckets[handle].bucket.free_list.next;
  70. } else {
  71. if (EG(objects).top == EG(objects).size) {
  72. EG(objects).size <<= 1;
  73. EG(objects).object_buckets = (zend_object_bucket *) erealloc(EG(objects).object_buckets, EG(objects).size * sizeof(zend_object_bucket));
  74. }
  75. handle = EG(objects).top++;
  76. }
  77. EG(objects).object_buckets[handle].valid = 1;
  78. EG(objects).object_buckets[handle].destructor_called = 0;
  79. EG(objects).object_buckets[handle].bucket.obj.refcount = 1;
  80. *object = &EG(objects).object_buckets[handle].bucket.obj.object;
  81. (*object)->ce = class_type;
  82. retval.handle = handle;
  83. retval.handlers = &std_object_handlers;
  84. #if ZEND_DEBUG_OBJECTS
  85. fprintf(stderr, "Allocated object id #%d\n", handle);
  86. #endif
  87. return retval;
  88. }
  89. zend_object *zend_objects_get_address(zval *zobject)
  90. {
  91. zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
  92. TSRMLS_FETCH();
  93. if (!EG(objects).object_buckets[handle].valid) {
  94. zend_error(E_ERROR, "Trying to access invalid object");
  95. }
  96. return &EG(objects).object_buckets[handle].bucket.obj.object;
  97. }
  98. void zend_objects_add_ref(zval *object TSRMLS_DC)
  99. {
  100. zend_object_handle handle = Z_OBJ_HANDLE_P(object);
  101. if (!EG(objects).object_buckets[handle].valid) {
  102. zend_error(E_ERROR, "Trying to add reference to invalid object");
  103. }
  104. EG(objects).object_buckets[handle].bucket.obj.refcount++;
  105. #if ZEND_DEBUG_OBJECTS
  106. fprintf(stderr, "Increased refcount of object id #%d\n", handle);
  107. #endif
  108. }
  109. void zend_objects_delete_obj(zval *zobject TSRMLS_DC)
  110. {
  111. zend_object *object;
  112. zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
  113. if (!EG(objects).object_buckets[handle].valid) {
  114. zend_error(E_ERROR, "Trying to delete invalid object");
  115. }
  116. object = &EG(objects).object_buckets[handle].bucket.obj.object;
  117. if (!EG(objects).object_buckets[handle].destructor_called) {
  118. EG(objects).object_buckets[handle].destructor_called = 1;
  119. zend_objects_destroy_object(object, handle TSRMLS_CC);
  120. }
  121. EG(objects).object_buckets[handle].valid = 0;
  122. #if ZEND_DEBUG_OBJECTS
  123. fprintf(stderr, "Deleted object id #%d\n", handle);
  124. #endif
  125. }
  126. #define ZEND_OBJECTS_ADD_TO_FREE_LIST() \
  127. EG(objects).object_buckets[handle].bucket.free_list.next = EG(objects).free_list_head; \
  128. EG(objects).free_list_head = handle; \
  129. EG(objects).object_buckets[handle].valid = 0;
  130. void zend_objects_del_ref(zval *zobject TSRMLS_DC)
  131. {
  132. zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
  133. if (--EG(objects).object_buckets[handle].bucket.obj.refcount == 0) {
  134. zend_object *object;
  135. do {
  136. if (EG(objects).object_buckets[handle].valid) {
  137. if (!EG(objects).object_buckets[handle].destructor_called) {
  138. object = &EG(objects).object_buckets[handle].bucket.obj.object;
  139. EG(objects).object_buckets[handle].destructor_called = 1;
  140. zend_objects_destroy_object(object, handle TSRMLS_CC);
  141. if (EG(objects).object_buckets[handle].bucket.obj.refcount == 0) {
  142. ZEND_OBJECTS_ADD_TO_FREE_LIST();
  143. }
  144. break;
  145. }
  146. }
  147. ZEND_OBJECTS_ADD_TO_FREE_LIST();
  148. } while (0);
  149. #if ZEND_DEBUG_OBJECTS
  150. fprintf(stderr, "Deallocated object id #%d\n", handle);
  151. #endif
  152. }
  153. #if ZEND_DEBUG_OBJECTS
  154. else {
  155. fprintf(stderr, "Decreased refcount of object id #%d\n", handle);
  156. }
  157. #endif
  158. }
  159. zend_object_value zend_objects_clone_obj(zval *zobject TSRMLS_DC)
  160. {
  161. zend_object_value retval;
  162. zend_object *old_object;
  163. zend_object *new_object;
  164. zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
  165. if (!EG(objects).object_buckets[handle].valid) {
  166. zend_error(E_ERROR, "Trying to clone invalid object");
  167. }
  168. old_object = &EG(objects).object_buckets[handle].bucket.obj.object;
  169. retval = zend_objects_new(&new_object, old_object->ce);
  170. if (old_object->ce->clone) {
  171. zval *old_obj;
  172. zval *new_obj;
  173. zval *clone_func_name;
  174. zval *retval_ptr;
  175. HashTable symbol_table;
  176. MAKE_STD_ZVAL(new_obj);
  177. new_obj->type = IS_OBJECT;
  178. new_obj->value.obj = retval;
  179. zval_copy_ctor(new_obj);
  180. MAKE_STD_ZVAL(old_obj);
  181. old_obj->type = IS_OBJECT;
  182. old_obj->value.obj.handle = handle;
  183. old_obj->value.obj.handlers = &std_object_handlers; /* If we reached here than the handlers are standrd */
  184. zval_copy_ctor(old_obj);
  185. /* FIXME: Optimize this so that we use the old_object->ce->clone function pointer instead of the name */
  186. MAKE_STD_ZVAL(clone_func_name);
  187. clone_func_name->type = IS_STRING;
  188. clone_func_name->value.str.val = estrndup("__clone", sizeof("__clone")-1);
  189. clone_func_name->value.str.len = sizeof("__clone")-1;
  190. ALLOC_HASHTABLE(new_object->properties);
  191. zend_hash_init(new_object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
  192. ZEND_INIT_SYMTABLE(&symbol_table);
  193. ZEND_SET_SYMBOL(&symbol_table, "clone", old_obj);
  194. call_user_function_ex(NULL, &new_obj, clone_func_name, &retval_ptr, 0, NULL, 0, &symbol_table TSRMLS_CC);
  195. zend_hash_destroy(&symbol_table);
  196. zval_ptr_dtor(&new_obj);
  197. zval_ptr_dtor(&clone_func_name);
  198. zval_ptr_dtor(&retval_ptr);
  199. } else {
  200. ALLOC_HASHTABLE(new_object->properties);
  201. zend_hash_init(new_object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
  202. zend_hash_copy(new_object->properties, old_object->properties, (copy_ctor_func_t) zval_add_ref, (void *) NULL /* Not used anymore */, sizeof(zval *));
  203. }
  204. return retval;
  205. }