Annotation of embedaddon/php/Zend/zend_gc.c, revision 1.1.1.1
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: David Wang <planetbeing@gmail.com> |
16: | Dmitry Stogov <dmitry@zend.com> |
17: +----------------------------------------------------------------------+
18: */
19:
20: /* $Id: zend_gc.c 321634 2012-01-01 13:15:04Z felipe $ */
21:
22: #include "zend.h"
23: #include "zend_API.h"
24:
25: #define GC_ROOT_BUFFER_MAX_ENTRIES 10000
26:
27: #ifdef ZTS
28: ZEND_API int gc_globals_id;
29: #else
30: ZEND_API zend_gc_globals gc_globals;
31: #endif
32:
33: static void root_buffer_dtor(zend_gc_globals *gc_globals TSRMLS_DC)
34: {
35: if (gc_globals->buf) {
36: free(gc_globals->buf);
37: gc_globals->buf = NULL;
38: }
39: }
40:
41: static void gc_globals_ctor_ex(zend_gc_globals *gc_globals TSRMLS_DC)
42: {
43: gc_globals->gc_enabled = 0;
44: gc_globals->gc_active = 0;
45:
46: gc_globals->buf = NULL;
47:
48: gc_globals->roots.next = &gc_globals->roots;
49: gc_globals->roots.prev = &gc_globals->roots;
50: gc_globals->unused = NULL;
51: gc_globals->zval_to_free = NULL;
52: gc_globals->free_list = NULL;
53: gc_globals->next_to_free = NULL;
54:
55: gc_globals->gc_runs = 0;
56: gc_globals->collected = 0;
57:
58: #if GC_BENCH
59: gc_globals->root_buf_length = 0;
60: gc_globals->root_buf_peak = 0;
61: gc_globals->zval_possible_root = 0;
62: gc_globals->zobj_possible_root = 0;
63: gc_globals->zval_buffered = 0;
64: gc_globals->zobj_buffered = 0;
65: gc_globals->zval_remove_from_buffer = 0;
66: gc_globals->zobj_remove_from_buffer = 0;
67: gc_globals->zval_marked_grey = 0;
68: gc_globals->zobj_marked_grey = 0;
69: #endif
70: }
71:
72: ZEND_API void gc_globals_ctor(TSRMLS_D)
73: {
74: #ifdef ZTS
75: ts_allocate_id(&gc_globals_id, sizeof(zend_gc_globals), (ts_allocate_ctor) gc_globals_ctor_ex, (ts_allocate_dtor) root_buffer_dtor);
76: #else
77: gc_globals_ctor_ex(&gc_globals);
78: #endif
79: }
80:
81: ZEND_API void gc_globals_dtor(TSRMLS_D)
82: {
83: #ifndef ZTS
84: root_buffer_dtor(&gc_globals TSRMLS_DC);
85: #endif
86: }
87:
88: ZEND_API void gc_reset(TSRMLS_D)
89: {
90: GC_G(gc_runs) = 0;
91: GC_G(collected) = 0;
92:
93: #if GC_BENCH
94: GC_G(root_buf_length) = 0;
95: GC_G(root_buf_peak) = 0;
96: GC_G(zval_possible_root) = 0;
97: GC_G(zobj_possible_root) = 0;
98: GC_G(zval_buffered) = 0;
99: GC_G(zobj_buffered) = 0;
100: GC_G(zval_remove_from_buffer) = 0;
101: GC_G(zobj_remove_from_buffer) = 0;
102: GC_G(zval_marked_grey) = 0;
103: GC_G(zobj_marked_grey) = 0;
104: #endif
105:
106: GC_G(roots).next = &GC_G(roots);
107: GC_G(roots).prev = &GC_G(roots);
108:
109: if (GC_G(buf)) {
110: GC_G(unused) = NULL;
111: GC_G(first_unused) = GC_G(buf);
112:
113: GC_G(zval_to_free) = NULL;
114: } else {
115: GC_G(unused) = NULL;
116: GC_G(first_unused) = NULL;
117: GC_G(last_unused) = NULL;
118: }
119: }
120:
121: ZEND_API void gc_init(TSRMLS_D)
122: {
123: if (GC_G(buf) == NULL && GC_G(gc_enabled)) {
124: GC_G(buf) = (gc_root_buffer*) malloc(sizeof(gc_root_buffer) * GC_ROOT_BUFFER_MAX_ENTRIES);
125: GC_G(last_unused) = &GC_G(buf)[GC_ROOT_BUFFER_MAX_ENTRIES];
126: gc_reset(TSRMLS_C);
127: }
128: }
129:
130: ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC)
131: {
132: if (UNEXPECTED(GC_G(free_list) != NULL &&
133: GC_ZVAL_ADDRESS(zv) != NULL &&
134: GC_ZVAL_GET_COLOR(zv) == GC_BLACK) &&
135: (GC_ZVAL_ADDRESS(zv) < GC_G(buf) ||
136: GC_ZVAL_ADDRESS(zv) >= GC_G(last_unused))) {
137: /* The given zval is a garbage that is going to be deleted by
138: * currently running GC */
139: return;
140: }
141:
142: if (zv->type == IS_OBJECT) {
143: GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv);
144: return;
145: }
146:
147: GC_BENCH_INC(zval_possible_root);
148:
149: if (GC_ZVAL_GET_COLOR(zv) != GC_PURPLE) {
150: GC_ZVAL_SET_PURPLE(zv);
151:
152: if (!GC_ZVAL_ADDRESS(zv)) {
153: gc_root_buffer *newRoot = GC_G(unused);
154:
155: if (newRoot) {
156: GC_G(unused) = newRoot->prev;
157: } else if (GC_G(first_unused) != GC_G(last_unused)) {
158: newRoot = GC_G(first_unused);
159: GC_G(first_unused)++;
160: } else {
161: if (!GC_G(gc_enabled)) {
162: GC_ZVAL_SET_BLACK(zv);
163: return;
164: }
165: zv->refcount__gc++;
166: gc_collect_cycles(TSRMLS_C);
167: zv->refcount__gc--;
168: newRoot = GC_G(unused);
169: if (!newRoot) {
170: return;
171: }
172: GC_ZVAL_SET_PURPLE(zv);
173: GC_G(unused) = newRoot->prev;
174: }
175:
176: newRoot->next = GC_G(roots).next;
177: newRoot->prev = &GC_G(roots);
178: GC_G(roots).next->prev = newRoot;
179: GC_G(roots).next = newRoot;
180:
181: GC_ZVAL_SET_ADDRESS(zv, newRoot);
182:
183: newRoot->handle = 0;
184: newRoot->u.pz = zv;
185:
186: GC_BENCH_INC(zval_buffered);
187: GC_BENCH_INC(root_buf_length);
188: GC_BENCH_PEAK(root_buf_peak, root_buf_length);
189: }
190: }
191: }
192:
193: ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC)
194: {
195: struct _store_object *obj;
196:
197: if (UNEXPECTED(Z_OBJ_HT_P(zv)->get_properties == NULL ||
198: EG(objects_store).object_buckets == NULL)) {
199: return;
200: }
201:
202: GC_BENCH_INC(zobj_possible_root);
203:
204: obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj;
205: if (GC_GET_COLOR(obj->buffered) != GC_PURPLE) {
206: GC_SET_PURPLE(obj->buffered);
207: if (!GC_ADDRESS(obj->buffered)) {
208: gc_root_buffer *newRoot = GC_G(unused);
209:
210: if (newRoot) {
211: GC_G(unused) = newRoot->prev;
212: } else if (GC_G(first_unused) != GC_G(last_unused)) {
213: newRoot = GC_G(first_unused);
214: GC_G(first_unused)++;
215: } else {
216: if (!GC_G(gc_enabled)) {
217: GC_ZVAL_SET_BLACK(zv);
218: return;
219: }
220: zv->refcount__gc++;
221: gc_collect_cycles(TSRMLS_C);
222: zv->refcount__gc--;
223: newRoot = GC_G(unused);
224: if (!newRoot) {
225: return;
226: }
227: obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj;
228: GC_SET_PURPLE(obj->buffered);
229: GC_G(unused) = newRoot->prev;
230: }
231:
232: newRoot->next = GC_G(roots).next;
233: newRoot->prev = &GC_G(roots);
234: GC_G(roots).next->prev = newRoot;
235: GC_G(roots).next = newRoot;
236:
237: GC_SET_ADDRESS(obj->buffered, newRoot);
238:
239: newRoot->handle = Z_OBJ_HANDLE_P(zv);
240: newRoot->u.handlers = Z_OBJ_HT_P(zv);
241:
242: GC_BENCH_INC(zobj_buffered);
243: GC_BENCH_INC(root_buf_length);
244: GC_BENCH_PEAK(root_buf_peak, root_buf_length);
245: }
246: }
247: }
248:
249: ZEND_API void gc_remove_zval_from_buffer(zval *zv TSRMLS_DC)
250: {
251: gc_root_buffer* root_buffer = GC_ADDRESS(((zval_gc_info*)zv)->u.buffered);
252:
253: if (UNEXPECTED(GC_G(free_list) != NULL &&
254: GC_ZVAL_GET_COLOR(zv) == GC_BLACK) &&
255: (GC_ZVAL_ADDRESS(zv) < GC_G(buf) ||
256: GC_ZVAL_ADDRESS(zv) >= GC_G(last_unused))) {
257: /* The given zval is a garbage that is going to be deleted by
258: * currently running GC */
259: if (GC_G(next_to_free) == (zval_gc_info*)zv) {
260: GC_G(next_to_free) = ((zval_gc_info*)zv)->u.next;
261: }
262: return;
263: }
264: GC_BENCH_INC(zval_remove_from_buffer);
265: GC_REMOVE_FROM_BUFFER(root_buffer);
266: ((zval_gc_info*)zv)->u.buffered = NULL;
267: }
268:
269: static void zval_scan_black(zval *pz TSRMLS_DC)
270: {
271: Bucket *p;
272:
273: tail_call:
274: p = NULL;
275: GC_ZVAL_SET_BLACK(pz);
276:
277: if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
278: struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
279:
280: obj->refcount++;
281: if (GC_GET_COLOR(obj->buffered) != GC_BLACK) {
282: GC_SET_BLACK(obj->buffered);
283: if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
284: Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
285: HashTable *props = Z_OBJPROP_P(pz);
286: if(!props) {
287: return;
288: }
289: p = props->pListHead;
290: }
291: }
292: } else if (Z_TYPE_P(pz) == IS_ARRAY) {
293: if (Z_ARRVAL_P(pz) != &EG(symbol_table)) {
294: p = Z_ARRVAL_P(pz)->pListHead;
295: }
296: }
297: while (p != NULL) {
298: pz = *(zval**)p->pData;
299: if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
300: pz->refcount__gc++;
301: }
302: if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
303: if (p->pListNext == NULL) {
304: goto tail_call;
305: } else {
306: zval_scan_black(pz TSRMLS_CC);
307: }
308: }
309: p = p->pListNext;
310: }
311: }
312:
313: static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC)
314: {
315: Bucket *p;
316:
317: GC_SET_BLACK(obj->buffered);
318: if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
319: Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
320: HashTable *props = Z_OBJPROP_P(pz);
321: if(!props) {
322: return;
323: }
324: p = props->pListHead;
325: while (p != NULL) {
326: pz = *(zval**)p->pData;
327: if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
328: pz->refcount__gc++;
329: }
330: if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
331: zval_scan_black(pz TSRMLS_CC);
332: }
333: p = p->pListNext;
334: }
335: }
336: }
337:
338: static void zval_mark_grey(zval *pz TSRMLS_DC)
339: {
340: Bucket *p;
341:
342: tail_call:
343: if (GC_ZVAL_GET_COLOR(pz) != GC_GREY) {
344: p = NULL;
345: GC_BENCH_INC(zval_marked_grey);
346: GC_ZVAL_SET_COLOR(pz, GC_GREY);
347:
348: if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
349: struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
350:
351: obj->refcount--;
352: if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
353: GC_BENCH_INC(zobj_marked_grey);
354: GC_SET_COLOR(obj->buffered, GC_GREY);
355: if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
356: Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
357: HashTable *props = Z_OBJPROP_P(pz);
358: if(!props) {
359: return;
360: }
361: p = props->pListHead;
362: }
363: }
364: } else if (Z_TYPE_P(pz) == IS_ARRAY) {
365: if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
366: GC_ZVAL_SET_BLACK(pz);
367: } else {
368: p = Z_ARRVAL_P(pz)->pListHead;
369: }
370: }
371: while (p != NULL) {
372: pz = *(zval**)p->pData;
373: if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
374: pz->refcount__gc--;
375: }
376: if (p->pListNext == NULL) {
377: goto tail_call;
378: } else {
379: zval_mark_grey(pz TSRMLS_CC);
380: }
381: p = p->pListNext;
382: }
383: }
384: }
385:
386: static void zobj_mark_grey(struct _store_object *obj, zval *pz TSRMLS_DC)
387: {
388: Bucket *p;
389:
390: if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
391: GC_BENCH_INC(zobj_marked_grey);
392: GC_SET_COLOR(obj->buffered, GC_GREY);
393: if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
394: Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
395: HashTable *props = Z_OBJPROP_P(pz);
396: if(!props) {
397: return;
398: }
399: p = props->pListHead;
400: while (p != NULL) {
401: pz = *(zval**)p->pData;
402: if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
403: pz->refcount__gc--;
404: }
405: zval_mark_grey(pz TSRMLS_CC);
406: p = p->pListNext;
407: }
408: }
409: }
410: }
411:
412: static void gc_mark_roots(TSRMLS_D)
413: {
414: gc_root_buffer *current = GC_G(roots).next;
415:
416: while (current != &GC_G(roots)) {
417: if (current->handle) {
418: if (EG(objects_store).object_buckets) {
419: struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
420:
421: if (GC_GET_COLOR(obj->buffered) == GC_PURPLE) {
422: zval z;
423:
424: INIT_PZVAL(&z);
425: Z_OBJ_HANDLE(z) = current->handle;
426: Z_OBJ_HT(z) = current->u.handlers;
427: zobj_mark_grey(obj, &z TSRMLS_CC);
428: } else {
429: GC_SET_ADDRESS(obj->buffered, NULL);
430: GC_REMOVE_FROM_BUFFER(current);
431: }
432: }
433: } else {
434: if (GC_ZVAL_GET_COLOR(current->u.pz) == GC_PURPLE) {
435: zval_mark_grey(current->u.pz TSRMLS_CC);
436: } else {
437: GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
438: GC_REMOVE_FROM_BUFFER(current);
439: }
440: }
441: current = current->next;
442: }
443: }
444:
445: static int zval_scan(zval *pz TSRMLS_DC)
446: {
447: Bucket *p;
448:
449: tail_call:
450: if (GC_ZVAL_GET_COLOR(pz) == GC_GREY) {
451: p = NULL;
452: if (pz->refcount__gc > 0) {
453: zval_scan_black(pz TSRMLS_CC);
454: } else {
455: GC_ZVAL_SET_COLOR(pz, GC_WHITE);
456: if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
457: struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
458:
459: if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
460: if (obj->refcount > 0) {
461: zobj_scan_black(obj, pz TSRMLS_CC);
462: } else {
463: GC_SET_COLOR(obj->buffered, GC_WHITE);
464: if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
465: Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
466: HashTable *props = Z_OBJPROP_P(pz);
467: if(!props) {
468: return 0;
469: }
470: p = props->pListHead;
471: }
472: }
473: }
474: } else if (Z_TYPE_P(pz) == IS_ARRAY) {
475: if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
476: GC_ZVAL_SET_BLACK(pz);
477: } else {
478: p = Z_ARRVAL_P(pz)->pListHead;
479: }
480: }
481: }
482: while (p != NULL) {
483: if (p->pListNext == NULL) {
484: pz = *(zval**)p->pData;
485: goto tail_call;
486: } else {
487: zval_scan(*(zval**)p->pData TSRMLS_CC);
488: }
489: p = p->pListNext;
490: }
491: }
492: return 0;
493: }
494:
495: static void zobj_scan(zval *pz TSRMLS_DC)
496: {
497: Bucket *p;
498:
499: if (EG(objects_store).object_buckets) {
500: struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
501:
502: if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
503: if (obj->refcount > 0) {
504: zobj_scan_black(obj, pz TSRMLS_CC);
505: } else {
506: GC_SET_COLOR(obj->buffered, GC_WHITE);
507: if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
508: Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
509: HashTable *props = Z_OBJPROP_P(pz);
510: if(!props) {
511: return;
512: }
513: p = props->pListHead;
514: while (p != NULL) {
515: zval_scan(*(zval**)p->pData TSRMLS_CC);
516: p = p->pListNext;
517: }
518: }
519: }
520: }
521: }
522: }
523:
524: static void gc_scan_roots(TSRMLS_D)
525: {
526: gc_root_buffer *current = GC_G(roots).next;
527:
528: while (current != &GC_G(roots)) {
529: if (current->handle) {
530: zval z;
531:
532: INIT_PZVAL(&z);
533: Z_OBJ_HANDLE(z) = current->handle;
534: Z_OBJ_HT(z) = current->u.handlers;
535: zobj_scan(&z TSRMLS_CC);
536: } else {
537: zval_scan(current->u.pz TSRMLS_CC);
538: }
539: current = current->next;
540: }
541: }
542:
543: static void zval_collect_white(zval *pz TSRMLS_DC)
544: {
545: Bucket *p;
546:
547: tail_call:
548: if (((zval_gc_info*)(pz))->u.buffered == (gc_root_buffer*)GC_WHITE) {
549: p = NULL;
550: GC_ZVAL_SET_BLACK(pz);
551:
552: if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
553: struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
554:
555: if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
556: GC_SET_BLACK(obj->buffered);
557:
558: if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
559: Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
560: HashTable *props = Z_OBJPROP_P(pz);
561: if(!props) {
562: return;
563: }
564: p = props->pListHead;
565: }
566: }
567: } else {
568: if (Z_TYPE_P(pz) == IS_ARRAY) {
569: p = Z_ARRVAL_P(pz)->pListHead;
570: }
571: }
572:
573: /* restore refcount and put into list to free */
574: pz->refcount__gc++;
575: ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
576: GC_G(zval_to_free) = (zval_gc_info*)pz;
577:
578: while (p != NULL) {
579: pz = *(zval**)p->pData;
580: if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
581: pz->refcount__gc++;
582: }
583: if (p->pListNext == NULL) {
584: goto tail_call;
585: } else {
586: zval_collect_white(pz TSRMLS_CC);
587: }
588: p = p->pListNext;
589: }
590: }
591: }
592:
593: static void zobj_collect_white(zval *pz TSRMLS_DC)
594: {
595: Bucket *p;
596:
597: if (EG(objects_store).object_buckets) {
598: struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
599:
600: if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
601: GC_SET_BLACK(obj->buffered);
602:
603: if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
604: Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
605: HashTable *props = Z_OBJPROP_P(pz);
606: if(!props) {
607: return;
608: }
609: p = props->pListHead;
610: while (p != NULL) {
611: pz = *(zval**)p->pData;
612: if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
613: pz->refcount__gc++;
614: }
615: zval_collect_white(pz TSRMLS_CC);
616: p = p->pListNext;
617: }
618: }
619: }
620: }
621: }
622:
623: static void gc_collect_roots(TSRMLS_D)
624: {
625: gc_root_buffer *current = GC_G(roots).next;
626:
627: while (current != &GC_G(roots)) {
628: if (current->handle) {
629: if (EG(objects_store).object_buckets) {
630: struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
631: zval z;
632:
633: GC_SET_ADDRESS(obj->buffered, NULL);
634: INIT_PZVAL(&z);
635: Z_OBJ_HANDLE(z) = current->handle;
636: Z_OBJ_HT(z) = current->u.handlers;
637: zobj_collect_white(&z TSRMLS_CC);
638: }
639: } else {
640: GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
641: zval_collect_white(current->u.pz TSRMLS_CC);
642: }
643:
644: GC_REMOVE_FROM_BUFFER(current);
645: current = current->next;
646: }
647: }
648:
649: #define FREE_LIST_END ((zval_gc_info*)(~(zend_uintptr_t)GC_COLOR))
650:
651: ZEND_API int gc_collect_cycles(TSRMLS_D)
652: {
653: int count = 0;
654:
655: if (GC_G(roots).next != &GC_G(roots)) {
656: zval_gc_info *p, *q, *orig_free_list, *orig_next_to_free;
657:
658: if (GC_G(gc_active)) {
659: return 0;
660: }
661: GC_G(gc_runs)++;
662: GC_G(zval_to_free) = FREE_LIST_END;
663: GC_G(gc_active) = 1;
664: gc_mark_roots(TSRMLS_C);
665: gc_scan_roots(TSRMLS_C);
666: gc_collect_roots(TSRMLS_C);
667:
668: orig_free_list = GC_G(free_list);
669: orig_next_to_free = GC_G(next_to_free);
670: p = GC_G(free_list) = GC_G(zval_to_free);
671: GC_G(zval_to_free) = NULL;
672: GC_G(gc_active) = 0;
673:
674: /* First call destructors */
675: while (p != FREE_LIST_END) {
676: if (Z_TYPE(p->z) == IS_OBJECT) {
677: if (EG(objects_store).object_buckets &&
678: EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
679: EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0 &&
680: EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor &&
681: !EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called) {
682:
683: EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called = 1;
684: EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount++;
685: EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor(EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.object, Z_OBJ_HANDLE(p->z) TSRMLS_CC);
686: EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount--;
687: }
688: }
689: count++;
690: p = p->u.next;
691: }
692:
693: /* Destroy zvals */
694: p = GC_G(free_list);
695: while (p != FREE_LIST_END) {
696: GC_G(next_to_free) = p->u.next;
697: if (Z_TYPE(p->z) == IS_OBJECT) {
698: if (EG(objects_store).object_buckets &&
699: EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
700: EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0) {
701: EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1;
702: Z_TYPE(p->z) = IS_NULL;
703: zend_objects_store_del_ref_by_handle_ex(Z_OBJ_HANDLE(p->z), Z_OBJ_HT(p->z) TSRMLS_CC);
704: }
705: } else if (Z_TYPE(p->z) == IS_ARRAY) {
706: Z_TYPE(p->z) = IS_NULL;
707: zend_hash_destroy(Z_ARRVAL(p->z));
708: FREE_HASHTABLE(Z_ARRVAL(p->z));
709: } else {
710: zval_dtor(&p->z);
711: Z_TYPE(p->z) = IS_NULL;
712: }
713: p = GC_G(next_to_free);
714: }
715:
716: /* Free zvals */
717: p = GC_G(free_list);
718: while (p != FREE_LIST_END) {
719: q = p->u.next;
720: FREE_ZVAL_EX(&p->z);
721: p = q;
722: }
723: GC_G(collected) += count;
724: GC_G(free_list) = orig_free_list;
725: GC_G(next_to_free) = orig_next_to_free;
726: }
727:
728: return count;
729: }
730:
731: /*
732: * Local variables:
733: * tab-width: 4
734: * c-basic-offset: 4
735: * indent-tabs-mode: t
736: * End:
737: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>