1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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@php.net> |
17 +----------------------------------------------------------------------+
18 */
19
20 #ifndef ZEND_GC_H
21 #define ZEND_GC_H
22
23 #include "zend_hrtime.h"
24
25 #ifndef GC_BENCH
26 # define GC_BENCH 0
27 #endif
28
29 BEGIN_EXTERN_C()
30
31 typedef struct _zend_gc_status {
32 bool active;
33 bool gc_protected;
34 bool full;
35 uint32_t runs;
36 uint32_t collected;
37 uint32_t threshold;
38 uint32_t buf_size;
39 uint32_t num_roots;
40 zend_hrtime_t application_time;
41 zend_hrtime_t collector_time;
42 zend_hrtime_t dtor_time;
43 zend_hrtime_t free_time;
44 } zend_gc_status;
45
46 ZEND_API extern int (*gc_collect_cycles)(void);
47
48 ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref);
49 ZEND_API void ZEND_FASTCALL gc_remove_from_buffer(zend_refcounted *ref);
50
51 /* enable/disable automatic start of GC collection */
52 ZEND_API bool gc_enable(bool enable);
53 ZEND_API bool gc_enabled(void);
54
55 /* enable/disable possible root additions */
56 ZEND_API bool gc_protect(bool protect);
57 ZEND_API bool gc_protected(void);
58
59 #if GC_BENCH
60 void gc_bench_print(void);
61 #endif
62
63 /* The default implementation of the gc_collect_cycles callback. */
64 ZEND_API int zend_gc_collect_cycles(void);
65
66 ZEND_API void zend_gc_get_status(zend_gc_status *status);
67
68 void gc_globals_ctor(void);
69 void gc_globals_dtor(void);
70 void gc_reset(void);
71
72 #ifdef ZTS
73 size_t zend_gc_globals_size(void);
74 #endif
75
76 #define GC_REMOVE_FROM_BUFFER(p) do { \
77 zend_refcounted *_p = (zend_refcounted*)(p); \
78 if (GC_TYPE_INFO(_p) & GC_INFO_MASK) { \
79 gc_remove_from_buffer(_p); \
80 } \
81 } while (0)
82
83 #define GC_MAY_LEAK(ref) \
84 ((GC_TYPE_INFO(ref) & \
85 (GC_INFO_MASK | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))) == 0)
86
gc_check_possible_root(zend_refcounted * ref)87 static zend_always_inline void gc_check_possible_root(zend_refcounted *ref)
88 {
89 if (EXPECTED(GC_TYPE_INFO(ref) == GC_REFERENCE)) {
90 zval *zv = &((zend_reference*)ref)->val;
91
92 if (!Z_COLLECTABLE_P(zv)) {
93 return;
94 }
95 ref = Z_COUNTED_P(zv);
96 }
97 if (UNEXPECTED(GC_MAY_LEAK(ref))) {
98 gc_possible_root(ref);
99 }
100 }
101
gc_check_possible_root_no_ref(zend_refcounted * ref)102 static zend_always_inline void gc_check_possible_root_no_ref(zend_refcounted *ref)
103 {
104 ZEND_ASSERT(GC_TYPE_INFO(ref) != GC_REFERENCE);
105 if (UNEXPECTED(GC_MAY_LEAK(ref))) {
106 gc_possible_root(ref);
107 }
108 }
109
110 /* These APIs can be used to simplify object get_gc implementations
111 * over heterogeneous structures. See zend_generator_get_gc() for
112 * a usage example. */
113
114 typedef struct {
115 zval *cur;
116 zval *end;
117 zval *start;
118 } zend_get_gc_buffer;
119
120 ZEND_API zend_get_gc_buffer *zend_get_gc_buffer_create(void);
121 ZEND_API void zend_get_gc_buffer_grow(zend_get_gc_buffer *gc_buffer);
122
zend_get_gc_buffer_add_zval(zend_get_gc_buffer * gc_buffer,zval * zv)123 static zend_always_inline void zend_get_gc_buffer_add_zval(
124 zend_get_gc_buffer *gc_buffer, zval *zv) {
125 if (Z_REFCOUNTED_P(zv)) {
126 if (UNEXPECTED(gc_buffer->cur == gc_buffer->end)) {
127 zend_get_gc_buffer_grow(gc_buffer);
128 }
129 ZVAL_COPY_VALUE(gc_buffer->cur, zv);
130 gc_buffer->cur++;
131 }
132 }
133
zend_get_gc_buffer_add_obj(zend_get_gc_buffer * gc_buffer,zend_object * obj)134 static zend_always_inline void zend_get_gc_buffer_add_obj(
135 zend_get_gc_buffer *gc_buffer, zend_object *obj) {
136 if (UNEXPECTED(gc_buffer->cur == gc_buffer->end)) {
137 zend_get_gc_buffer_grow(gc_buffer);
138 }
139 ZVAL_OBJ(gc_buffer->cur, obj);
140 gc_buffer->cur++;
141 }
142
zend_get_gc_buffer_add_ptr(zend_get_gc_buffer * gc_buffer,void * ptr)143 static zend_always_inline void zend_get_gc_buffer_add_ptr(
144 zend_get_gc_buffer *gc_buffer, void *ptr) {
145 if (UNEXPECTED(gc_buffer->cur == gc_buffer->end)) {
146 zend_get_gc_buffer_grow(gc_buffer);
147 }
148 ZVAL_PTR(gc_buffer->cur, ptr);
149 gc_buffer->cur++;
150 }
151
zend_get_gc_buffer_use(zend_get_gc_buffer * gc_buffer,zval ** table,int * n)152 static zend_always_inline void zend_get_gc_buffer_use(
153 zend_get_gc_buffer *gc_buffer, zval **table, int *n) {
154 *table = gc_buffer->start;
155 *n = gc_buffer->cur - gc_buffer->start;
156 }
157
158 END_EXTERN_C()
159
160 #endif /* ZEND_GC_H */
161