Annotation of embedaddon/php/Zend/zend_objects_API.c, revision 1.1.1.4
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | Zend Engine |
4: +----------------------------------------------------------------------+
1.1.1.3 misho 5: | Copyright (c) 1998-2013 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>