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