1: /*
2: +----------------------------------------------------------------------+
3: | Zend Engine |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1998-2014 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.h,v 1.1.1.4 2014/06/15 20:04:03 misho Exp $ */
21:
22: #ifndef ZEND_GC_H
23: #define ZEND_GC_H
24:
25: #ifndef GC_BENCH
26: # define GC_BENCH 0
27: #endif
28:
29: #if GC_BENCH
30: # define GC_BENCH_INC(counter) GC_G(counter)++
31: # define GC_BENCH_DEC(counter) GC_G(counter)--
32: # define GC_BENCH_PEAK(peak, counter) do { \
33: if (GC_G(counter) > GC_G(peak)) { \
34: GC_G(peak) = GC_G(counter); \
35: } \
36: } while (0)
37: #else
38: # define GC_BENCH_INC(counter)
39: # define GC_BENCH_DEC(counter)
40: # define GC_BENCH_PEAK(peak, counter)
41: #endif
42:
43: #define GC_COLOR 0x03
44:
45: #define GC_BLACK 0x00
46: #define GC_WHITE 0x01
47: #define GC_GREY 0x02
48: #define GC_PURPLE 0x03
49:
50: #define GC_ADDRESS(v) \
51: ((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR))
52: #define GC_SET_ADDRESS(v, a) \
53: (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & GC_COLOR) | ((zend_uintptr_t)(a))))
54: #define GC_GET_COLOR(v) \
55: (((zend_uintptr_t)(v)) & GC_COLOR)
56: #define GC_SET_COLOR(v, c) \
57: (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & ~GC_COLOR) | (c)))
58: #define GC_SET_BLACK(v) \
59: (v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR))
60: #define GC_SET_PURPLE(v) \
61: (v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) | GC_PURPLE))
62:
63: #define GC_ZVAL_INIT(z) \
64: ((zval_gc_info*)(z))->u.buffered = NULL
65: #define GC_ZVAL_ADDRESS(v) \
66: GC_ADDRESS(((zval_gc_info*)(v))->u.buffered)
67: #define GC_ZVAL_SET_ADDRESS(v, a) \
68: GC_SET_ADDRESS(((zval_gc_info*)(v))->u.buffered, (a))
69: #define GC_ZVAL_GET_COLOR(v) \
70: GC_GET_COLOR(((zval_gc_info*)(v))->u.buffered)
71: #define GC_ZVAL_SET_COLOR(v, c) \
72: GC_SET_COLOR(((zval_gc_info*)(v))->u.buffered, (c))
73: #define GC_ZVAL_SET_BLACK(v) \
74: GC_SET_BLACK(((zval_gc_info*)(v))->u.buffered)
75: #define GC_ZVAL_SET_PURPLE(v) \
76: GC_SET_PURPLE(((zval_gc_info*)(v))->u.buffered)
77:
78: #define GC_OBJ_INIT(z) \
79: (z)->buffered = NULL
80:
81: typedef struct _gc_root_buffer {
82: struct _gc_root_buffer *prev; /* double-linked list */
83: struct _gc_root_buffer *next;
84: zend_object_handle handle; /* must be 0 for zval */
85: union {
86: zval *pz;
87: const zend_object_handlers *handlers;
88: } u;
89: } gc_root_buffer;
90:
91: typedef struct _zval_gc_info {
92: zval z;
93: union {
94: gc_root_buffer *buffered;
95: struct _zval_gc_info *next;
96: } u;
97: } zval_gc_info;
98:
99: typedef struct _zend_gc_globals {
100: zend_bool gc_enabled;
101: zend_bool gc_active;
102:
103: gc_root_buffer *buf; /* preallocated arrays of buffers */
104: gc_root_buffer roots; /* list of possible roots of cycles */
105: gc_root_buffer *unused; /* list of unused buffers */
106: gc_root_buffer *first_unused; /* pointer to first unused buffer */
107: gc_root_buffer *last_unused; /* pointer to last unused buffer */
108:
109: zval_gc_info *zval_to_free; /* temporary list of zvals to free */
110: zval_gc_info *free_list;
111: zval_gc_info *next_to_free;
112:
113: zend_uint gc_runs;
114: zend_uint collected;
115:
116: #if GC_BENCH
117: zend_uint root_buf_length;
118: zend_uint root_buf_peak;
119: zend_uint zval_possible_root;
120: zend_uint zobj_possible_root;
121: zend_uint zval_buffered;
122: zend_uint zobj_buffered;
123: zend_uint zval_remove_from_buffer;
124: zend_uint zobj_remove_from_buffer;
125: zend_uint zval_marked_grey;
126: zend_uint zobj_marked_grey;
127: #endif
128:
129: } zend_gc_globals;
130:
131: #ifdef ZTS
132: BEGIN_EXTERN_C()
133: ZEND_API extern int gc_globals_id;
134: END_EXTERN_C()
135: #define GC_G(v) TSRMG(gc_globals_id, zend_gc_globals *, v)
136: #else
137: #define GC_G(v) (gc_globals.v)
138: extern ZEND_API zend_gc_globals gc_globals;
139: #endif
140:
141: BEGIN_EXTERN_C()
142: ZEND_API int gc_collect_cycles(TSRMLS_D);
143: ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC);
144: ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC);
145: ZEND_API void gc_remove_zval_from_buffer(zval *zv TSRMLS_DC);
146: ZEND_API void gc_globals_ctor(TSRMLS_D);
147: ZEND_API void gc_globals_dtor(TSRMLS_D);
148: ZEND_API void gc_init(TSRMLS_D);
149: ZEND_API void gc_reset(TSRMLS_D);
150: END_EXTERN_C()
151:
152: #define GC_ZVAL_CHECK_POSSIBLE_ROOT(z) \
153: gc_zval_check_possible_root((z) TSRMLS_CC)
154:
155: #define GC_REMOVE_FROM_BUFFER(current) \
156: gc_remove_from_buffer((current) TSRMLS_CC)
157:
158: #define GC_REMOVE_ZVAL_FROM_BUFFER(z) \
159: if (GC_ADDRESS(((zval_gc_info*)z)->u.buffered)) { \
160: gc_remove_zval_from_buffer(z TSRMLS_CC); \
161: }
162:
163: #define GC_ZOBJ_CHECK_POSSIBLE_ROOT(zobject) \
164: do { \
165: if (EXPECTED(EG(objects_store).object_buckets != NULL) && \
166: EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zobject)].valid) { \
167: gc_zobj_possible_root(zobject TSRMLS_CC); \
168: } \
169: } while (0)
170:
171: #define GC_REMOVE_ZOBJ_FROM_BUFFER(obj) \
172: do { \
173: if (GC_ADDRESS((obj)->buffered) && !GC_G(gc_active)) { \
174: GC_BENCH_INC(zobj_remove_from_buffer); \
175: GC_REMOVE_FROM_BUFFER(GC_ADDRESS((obj)->buffered)); \
176: (obj)->buffered = NULL; \
177: } \
178: } while (0)
179:
180: static zend_always_inline void gc_zval_check_possible_root(zval *z TSRMLS_DC)
181: {
182: if (z->type == IS_ARRAY || z->type == IS_OBJECT) {
183: gc_zval_possible_root(z TSRMLS_CC);
184: }
185: }
186:
187: static zend_always_inline void gc_remove_from_buffer(gc_root_buffer *root TSRMLS_DC)
188: {
189: root->next->prev = root->prev;
190: root->prev->next = root->next;
191: root->prev = GC_G(unused);
192: GC_G(unused) = root;
193: GC_BENCH_DEC(root_buf_length);
194: }
195:
196: #define ALLOC_PERMANENT_ZVAL(z) \
197: do { \
198: (z) = (zval*)malloc(sizeof(zval_gc_info)); \
199: GC_ZVAL_INIT(z); \
200: } while (0)
201:
202: /* The following macros override macros from zend_alloc.h */
203: #undef ALLOC_ZVAL
204: #define ALLOC_ZVAL(z) \
205: do { \
206: (z) = (zval*)emalloc(sizeof(zval_gc_info)); \
207: GC_ZVAL_INIT(z); \
208: } while (0)
209:
210: #undef FREE_ZVAL
211: #define FREE_ZVAL(z) \
212: do { \
213: GC_REMOVE_ZVAL_FROM_BUFFER(z); \
214: efree(z); \
215: } while (0)
216:
217: #undef ALLOC_ZVAL_REL
218: #define ALLOC_ZVAL_REL(z) \
219: do { \
220: (z) = (zval*)emalloc_rel(sizeof(zval_gc_info)); \
221: GC_ZVAL_INIT(z); \
222: } while (0)
223:
224: #undef FREE_ZVAL_REL
225: #define FREE_ZVAL_REL(z) \
226: do { \
227: GC_REMOVE_ZVAL_FROM_BUFFER(z); \
228: efree_rel(z); \
229: } while (0)
230:
231: #define FREE_ZVAL_EX(z) \
232: efree(z)
233:
234: #define FREE_ZVAL_REL_EX(z) \
235: efree_rel(z)
236:
237: #endif /* ZEND_GC_H */
238:
239: /*
240: * Local variables:
241: * tab-width: 4
242: * c-basic-offset: 4
243: * indent-tabs-mode: t
244: * End:
245: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>