root/Zend/zend_objects_API.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_objects_store_init
  2. zend_objects_store_destroy
  3. zend_objects_store_call_destructors
  4. zend_objects_store_mark_destructed
  5. zend_objects_store_free_object_storage
  6. zend_objects_store_put
  7. zend_objects_store_get_refcount
  8. zend_objects_store_add_ref
  9. zend_objects_store_add_ref_by_handle
  10. zend_objects_store_del_ref
  11. zend_objects_store_del_ref_by_handle_ex
  12. zend_objects_store_clone_obj
  13. zend_object_store_get_object
  14. zend_object_store_get_object_by_handle
  15. zend_object_store_set_object
  16. zend_object_store_ctor_failed
  17. zend_objects_proxy_destroy
  18. zend_objects_proxy_free_storage
  19. zend_objects_proxy_clone
  20. zend_object_create_proxy
  21. zend_object_proxy_set
  22. zend_object_proxy_get
  23. zend_get_std_object_handlers

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend Engine                                                          |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 2.00 of the Zend license,     |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.zend.com/license/2_00.txt.                                |
  11    | If you did not receive a copy of the Zend license and are unable to  |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@zend.com so we can mail you a copy immediately.              |
  14    +----------------------------------------------------------------------+
  15    | Authors: Andi Gutmans <andi@zend.com>                                |
  16    |          Zeev Suraski <zeev@zend.com>                                |
  17    +----------------------------------------------------------------------+
  18 */
  19 
  20 /* $Id$ */
  21 
  22 #include "zend.h"
  23 #include "zend_globals.h"
  24 #include "zend_variables.h"
  25 #include "zend_API.h"
  26 #include "zend_objects_API.h"
  27 
  28 #define ZEND_DEBUG_OBJECTS 0
  29 
  30 ZEND_API void zend_objects_store_init(zend_objects_store *objects, zend_uint init_size)
  31 {
  32         objects->object_buckets = (zend_object_store_bucket *) emalloc(init_size * sizeof(zend_object_store_bucket));
  33         objects->top = 1; /* Skip 0 so that handles are true */
  34         objects->size = init_size;
  35         objects->free_list_head = -1;
  36         memset(&objects->object_buckets[0], 0, sizeof(zend_object_store_bucket));
  37 }
  38 
  39 ZEND_API void zend_objects_store_destroy(zend_objects_store *objects)
  40 {
  41         efree(objects->object_buckets);
  42         objects->object_buckets = NULL;
  43 }
  44 
  45 ZEND_API void zend_objects_store_call_destructors(zend_objects_store *objects TSRMLS_DC)
  46 {
  47         zend_uint i = 1;
  48 
  49         for (i = 1; i < objects->top ; i++) {
  50                 if (objects->object_buckets[i].valid) {
  51                         struct _store_object *obj = &objects->object_buckets[i].bucket.obj;
  52 
  53                         if (!objects->object_buckets[i].destructor_called) {
  54                                 objects->object_buckets[i].destructor_called = 1;
  55                                 if (obj->dtor && obj->object) {
  56                                         obj->refcount++;
  57                                         obj->dtor(obj->object, i TSRMLS_CC);
  58                                         obj = &objects->object_buckets[i].bucket.obj;
  59                                         obj->refcount--;
  60 
  61                                         if (obj->refcount == 0) {
  62                                                 /* in case gc_collect_cycle is triggered before free_storage */
  63                                                 GC_REMOVE_ZOBJ_FROM_BUFFER(obj);
  64                                         }
  65                                 }
  66                         }
  67                 }
  68         }
  69 }
  70 
  71 ZEND_API void zend_objects_store_mark_destructed(zend_objects_store *objects TSRMLS_DC)
  72 {
  73         zend_uint i;
  74 
  75         if (!objects->object_buckets) {
  76                 return;
  77         }
  78         for (i = 1; i < objects->top ; i++) {
  79                 if (objects->object_buckets[i].valid) {
  80                         objects->object_buckets[i].destructor_called = 1;
  81                 }
  82         }
  83 }
  84 
  85 ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects TSRMLS_DC)
  86 {
  87         zend_uint i = 1;
  88 
  89         for (i = 1; i < objects->top ; i++) {
  90                 if (objects->object_buckets[i].valid) {
  91                         struct _store_object *obj = &objects->object_buckets[i].bucket.obj;
  92 
  93                         GC_REMOVE_ZOBJ_FROM_BUFFER(obj);
  94 
  95                         objects->object_buckets[i].valid = 0;
  96                         if (obj->free_storage) {
  97                                 obj->free_storage(obj->object TSRMLS_CC);
  98                         }
  99                         /* Not adding to free list as we are shutting down anyway */
 100                 }
 101         }
 102 }
 103 
 104 
 105 /* Store objects API */
 106 
 107 ZEND_API zend_object_handle zend_objects_store_put(void *object, zend_objects_store_dtor_t dtor, zend_objects_free_object_storage_t free_storage, zend_objects_store_clone_t clone TSRMLS_DC)
 108 {
 109         zend_object_handle handle;
 110         struct _store_object *obj;
 111 
 112         if (EG(objects_store).free_list_head != -1) {
 113                 handle = EG(objects_store).free_list_head;
 114                 EG(objects_store).free_list_head = EG(objects_store).object_buckets[handle].bucket.free_list.next;
 115         } else {
 116                 if (EG(objects_store).top == EG(objects_store).size) {
 117                         EG(objects_store).size <<= 1;
 118                         EG(objects_store).object_buckets = (zend_object_store_bucket *) erealloc(EG(objects_store).object_buckets, EG(objects_store).size * sizeof(zend_object_store_bucket));
 119                 }
 120                 handle = EG(objects_store).top++;
 121         }
 122         obj = &EG(objects_store).object_buckets[handle].bucket.obj;
 123         EG(objects_store).object_buckets[handle].destructor_called = 0;
 124         EG(objects_store).object_buckets[handle].valid = 1;
 125         EG(objects_store).object_buckets[handle].apply_count = 0;
 126 
 127         obj->refcount = 1;
 128         GC_OBJ_INIT(obj);
 129         obj->object = object;
 130         obj->dtor = dtor?dtor:(zend_objects_store_dtor_t)zend_objects_destroy_object;
 131         obj->free_storage = free_storage;
 132         obj->clone = clone;
 133         obj->handlers = NULL;
 134 
 135 #if ZEND_DEBUG_OBJECTS
 136         fprintf(stderr, "Allocated object id #%d\n", handle);
 137 #endif
 138         return handle;
 139 }
 140 
 141 ZEND_API zend_uint zend_objects_store_get_refcount(zval *object TSRMLS_DC)
 142 {
 143         zend_object_handle handle = Z_OBJ_HANDLE_P(object);
 144 
 145         return EG(objects_store).object_buckets[handle].bucket.obj.refcount;
 146 }
 147 
 148 ZEND_API void zend_objects_store_add_ref(zval *object TSRMLS_DC)
 149 {
 150         zend_object_handle handle = Z_OBJ_HANDLE_P(object);
 151 
 152         EG(objects_store).object_buckets[handle].bucket.obj.refcount++;
 153 #if ZEND_DEBUG_OBJECTS
 154         fprintf(stderr, "Increased refcount of object id #%d\n", handle);
 155 #endif
 156 }
 157 
 158 /*
 159  * Add a reference to an objects store entry given the object handle.
 160  */
 161 ZEND_API void zend_objects_store_add_ref_by_handle(zend_object_handle handle TSRMLS_DC)
 162 {
 163         EG(objects_store).object_buckets[handle].bucket.obj.refcount++;
 164 }
 165 
 166 #define ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST()                                                                                                                                   \
 167                         EG(objects_store).object_buckets[handle].bucket.free_list.next = EG(objects_store).free_list_head;      \
 168                         EG(objects_store).free_list_head = handle;                                                                                                                      \
 169                         EG(objects_store).object_buckets[handle].valid = 0;
 170 
 171 ZEND_API void zend_objects_store_del_ref(zval *zobject TSRMLS_DC)
 172 {
 173         zend_object_handle handle;
 174 
 175         handle = Z_OBJ_HANDLE_P(zobject);
 176 
 177         Z_ADDREF_P(zobject);
 178         zend_objects_store_del_ref_by_handle_ex(handle, Z_OBJ_HT_P(zobject) TSRMLS_CC);
 179         Z_DELREF_P(zobject);
 180 
 181         GC_ZOBJ_CHECK_POSSIBLE_ROOT(zobject);
 182 }
 183 
 184 /*
 185  * Delete a reference to an objects store entry given the object handle.
 186  */
 187 ZEND_API void zend_objects_store_del_ref_by_handle_ex(zend_object_handle handle, const zend_object_handlers *handlers TSRMLS_DC) /* {{{ */
 188 {
 189         struct _store_object *obj;
 190         int failure = 0;
 191 
 192         if (!EG(objects_store).object_buckets) {
 193                 return;
 194         }
 195 
 196         obj = &EG(objects_store).object_buckets[handle].bucket.obj;
 197 
 198         /*      Make sure we hold a reference count during the destructor call
 199                 otherwise, when the destructor ends the storage might be freed
 200                 when the refcount reaches 0 a second time
 201          */
 202         if (EG(objects_store).object_buckets[handle].valid) {
 203                 if (obj->refcount == 1) {
 204                         if (!EG(objects_store).object_buckets[handle].destructor_called) {
 205                                 EG(objects_store).object_buckets[handle].destructor_called = 1;
 206 
 207                                 if (obj->dtor) {
 208                                         if (handlers && !obj->handlers) {
 209                                                 obj->handlers = handlers;
 210                                         }
 211                                         zend_try {
 212                                                 obj->dtor(obj->object, handle TSRMLS_CC);
 213                                         } zend_catch {
 214                                                 failure = 1;
 215                                         } zend_end_try();
 216                                 }
 217                         }
 218                         
 219                         /* re-read the object from the object store as the store might have been reallocated in the dtor */
 220                         obj = &EG(objects_store).object_buckets[handle].bucket.obj;
 221 
 222                         if (obj->refcount == 1) {
 223                                 GC_REMOVE_ZOBJ_FROM_BUFFER(obj);
 224                                 if (obj->free_storage) {
 225                                         zend_try {
 226                                                 obj->free_storage(obj->object TSRMLS_CC);
 227                                         } zend_catch {
 228                                                 failure = 1;
 229                                         } zend_end_try();
 230                                 }
 231                                 ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST();
 232                         }
 233                 }
 234         }
 235 
 236         obj->refcount--;
 237 
 238 #if ZEND_DEBUG_OBJECTS
 239         if (obj->refcount == 0) {
 240                 fprintf(stderr, "Deallocated object id #%d\n", handle);
 241         } else {
 242                 fprintf(stderr, "Decreased refcount of object id #%d\n", handle);
 243         }
 244 #endif
 245         if (failure) {
 246                 zend_bailout();
 247         }
 248 }
 249 /* }}} */
 250 
 251 ZEND_API zend_object_value zend_objects_store_clone_obj(zval *zobject TSRMLS_DC)
 252 {
 253         zend_object_value retval;
 254         void *new_object;
 255         struct _store_object *obj;
 256         zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
 257 
 258         obj = &EG(objects_store).object_buckets[handle].bucket.obj;
 259 
 260         if (obj->clone == NULL) {
 261                 zend_error(E_CORE_ERROR, "Trying to clone uncloneable object of class %s", Z_OBJCE_P(zobject)->name);
 262         }
 263 
 264         obj->clone(obj->object, &new_object TSRMLS_CC);
 265         obj = &EG(objects_store).object_buckets[handle].bucket.obj;
 266 
 267         retval.handle = zend_objects_store_put(new_object, obj->dtor, obj->free_storage, obj->clone TSRMLS_CC);
 268         retval.handlers = Z_OBJ_HT_P(zobject);
 269         EG(objects_store).object_buckets[handle].bucket.obj.handlers = retval.handlers;
 270 
 271         return retval;
 272 }
 273 
 274 ZEND_API void *zend_object_store_get_object(const zval *zobject TSRMLS_DC)
 275 {
 276         zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
 277 
 278         return EG(objects_store).object_buckets[handle].bucket.obj.object;
 279 }
 280 
 281 /*
 282  * Retrieve an entry from the objects store given the object handle.
 283  */
 284 ZEND_API void *zend_object_store_get_object_by_handle(zend_object_handle handle TSRMLS_DC)
 285 {
 286         return EG(objects_store).object_buckets[handle].bucket.obj.object;
 287 }
 288 
 289 /* zend_object_store_set_object:
 290  * It is ONLY valid to call this function from within the constructor of an
 291  * overloaded object.  Its purpose is to set the object pointer for the object
 292  * when you can't possibly know its value until you have parsed the arguments
 293  * from the constructor function.  You MUST NOT use this function for any other
 294  * weird games, or call it at any other time after the object is constructed.
 295  * */
 296 ZEND_API void zend_object_store_set_object(zval *zobject, void *object TSRMLS_DC)
 297 {
 298         zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
 299 
 300         EG(objects_store).object_buckets[handle].bucket.obj.object = object;
 301 }
 302 
 303 
 304 /* Called when the ctor was terminated by an exception */
 305 ZEND_API void zend_object_store_ctor_failed(zval *zobject TSRMLS_DC)
 306 {
 307         zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
 308         zend_object_store_bucket *obj_bucket = &EG(objects_store).object_buckets[handle];
 309         
 310         obj_bucket->bucket.obj.handlers = Z_OBJ_HT_P(zobject);;
 311         obj_bucket->destructor_called = 1;
 312 }
 313 
 314 
 315 /* Proxy objects workings */
 316 typedef struct _zend_proxy_object {
 317         zval *object;
 318         zval *property;
 319 } zend_proxy_object;
 320 
 321 static zend_object_handlers zend_object_proxy_handlers;
 322 
 323 ZEND_API void zend_objects_proxy_destroy(zend_object *object, zend_object_handle handle TSRMLS_DC)
 324 {
 325 }
 326 
 327 ZEND_API void zend_objects_proxy_free_storage(zend_proxy_object *object TSRMLS_DC)
 328 {
 329         zval_ptr_dtor(&object->object);
 330         zval_ptr_dtor(&object->property);
 331         efree(object);
 332 }
 333 
 334 ZEND_API void zend_objects_proxy_clone(zend_proxy_object *object, zend_proxy_object **object_clone TSRMLS_DC)
 335 {
 336         *object_clone = emalloc(sizeof(zend_proxy_object));
 337         (*object_clone)->object = object->object;
 338         (*object_clone)->property = object->property;
 339         zval_add_ref(&(*object_clone)->property);
 340         zval_add_ref(&(*object_clone)->object);
 341 }
 342 
 343 ZEND_API zval *zend_object_create_proxy(zval *object, zval *member TSRMLS_DC)
 344 {
 345         zend_proxy_object *pobj = emalloc(sizeof(zend_proxy_object));
 346         zval *retval;
 347 
 348         pobj->object = object;
 349         zval_add_ref(&pobj->object);
 350         ALLOC_ZVAL(pobj->property);
 351         INIT_PZVAL_COPY(pobj->property, member);
 352         zval_copy_ctor(pobj->property);
 353 
 354         MAKE_STD_ZVAL(retval);
 355         Z_TYPE_P(retval) = IS_OBJECT;
 356         Z_OBJ_HANDLE_P(retval) = zend_objects_store_put(pobj, (zend_objects_store_dtor_t)zend_objects_proxy_destroy, (zend_objects_free_object_storage_t) zend_objects_proxy_free_storage, (zend_objects_store_clone_t) zend_objects_proxy_clone TSRMLS_CC);
 357         Z_OBJ_HT_P(retval) = &zend_object_proxy_handlers;
 358 
 359         return retval;
 360 }
 361 
 362 ZEND_API void zend_object_proxy_set(zval **property, zval *value TSRMLS_DC)
 363 {
 364         zend_proxy_object *probj = zend_object_store_get_object(*property TSRMLS_CC);
 365 
 366         if (Z_OBJ_HT_P(probj->object) && Z_OBJ_HT_P(probj->object)->write_property) {
 367                 Z_OBJ_HT_P(probj->object)->write_property(probj->object, probj->property, value, 0 TSRMLS_CC);
 368         } else {
 369                 zend_error(E_WARNING, "Cannot write property of object - no write handler defined");
 370         }
 371 }
 372 
 373 ZEND_API zval* zend_object_proxy_get(zval *property TSRMLS_DC)
 374 {
 375         zend_proxy_object *probj = zend_object_store_get_object(property TSRMLS_CC);
 376 
 377         if (Z_OBJ_HT_P(probj->object) && Z_OBJ_HT_P(probj->object)->read_property) {
 378                 return Z_OBJ_HT_P(probj->object)->read_property(probj->object, probj->property, BP_VAR_R, 0 TSRMLS_CC);
 379         } else {
 380                 zend_error(E_WARNING, "Cannot read property of object - no read handler defined");
 381         }
 382 
 383         return NULL;
 384 }
 385 
 386 ZEND_API zend_object_handlers *zend_get_std_object_handlers(void)
 387 {
 388         return &std_object_handlers;
 389 }
 390 
 391 static zend_object_handlers zend_object_proxy_handlers = {
 392         ZEND_OBJECTS_STORE_HANDLERS,
 393 
 394         NULL,                                           /* read_property */
 395         NULL,                                           /* write_property */
 396         NULL,                                           /* read dimension */
 397         NULL,                                           /* write_dimension */
 398         NULL,                                           /* get_property_ptr_ptr */
 399         zend_object_proxy_get,          /* get */
 400         zend_object_proxy_set,          /* set */
 401         NULL,                                           /* has_property */
 402         NULL,                                           /* unset_property */
 403         NULL,                                           /* has_dimension */
 404         NULL,                                           /* unset_dimension */
 405         NULL,                                           /* get_properties */
 406         NULL,                                           /* get_method */
 407         NULL,                                           /* call_method */
 408         NULL,                                           /* get_constructor */
 409         NULL,                                           /* get_class_entry */
 410         NULL,                                           /* get_class_name */
 411         NULL,                                           /* compare_objects */
 412         NULL,                                           /* cast_object */
 413         NULL,                                           /* count_elements */
 414 };
 415 
 416 
 417 /*
 418  * Local variables:
 419  * tab-width: 4
 420  * c-basic-offset: 4
 421  * indent-tabs-mode: t
 422  * End:
 423  */

/* [<][>][^][v][top][bottom][index][help] */