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