Annotation of embedaddon/php/Zend/zend_objects_API.c, revision 1.1.1.5

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | Zend Engine                                                          |
                      4:    +----------------------------------------------------------------------+
1.1.1.5 ! misho       5:    | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
1.1       misho       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: 
1.1.1.2   misho      20: /* $Id$ */
1.1       misho      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--;
1.1.1.4   misho      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:                                        }
1.1       misho      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;
1.1.1.3   misho     125:        EG(objects_store).object_buckets[handle].apply_count = 0;
1.1       misho     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: 
1.1.1.2   misho     323: ZEND_API void zend_objects_proxy_destroy(zend_object *object, zend_object_handle handle TSRMLS_DC)
                    324: {
                    325: }
                    326: 
1.1       misho     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);
1.1.1.2   misho     350:        ALLOC_ZVAL(pobj->property);
                    351:        INIT_PZVAL_COPY(pobj->property, member);
                    352:        zval_copy_ctor(pobj->property);
1.1       misho     353: 
                    354:        MAKE_STD_ZVAL(retval);
                    355:        Z_TYPE_P(retval) = IS_OBJECT;
1.1.1.2   misho     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);
1.1       misho     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) {
1.1.1.2   misho     367:                Z_OBJ_HT_P(probj->object)->write_property(probj->object, probj->property, value, 0 TSRMLS_CC);
1.1       misho     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) {
1.1.1.2   misho     378:                return Z_OBJ_HT_P(probj->object)->read_property(probj->object, probj->property, BP_VAR_R, 0 TSRMLS_CC);
1.1       misho     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:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>