1 /* 2 +----------------------------------------------------------------------+ 3 | Zend Engine | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1998-2018 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$ */ 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 0xc000 44 45 #define GC_BLACK 0x0000 46 #define GC_WHITE 0x8000 47 #define GC_GREY 0x4000 48 #define GC_PURPLE 0xc000 49 50 #define GC_ADDRESS(v) \ 51 ((v) & ~GC_COLOR) 52 #define GC_INFO_GET_COLOR(v) \ 53 (((zend_uintptr_t)(v)) & GC_COLOR) 54 #define GC_INFO_SET_ADDRESS(v, a) \ 55 do {(v) = ((v) & GC_COLOR) | (a);} while (0) 56 #define GC_INFO_SET_COLOR(v, c) \ 57 do {(v) = ((v) & ~GC_COLOR) | (c);} while (0) 58 #define GC_INFO_SET_BLACK(v) \ 59 do {(v) = (v) & ~GC_COLOR;} while (0) 60 #define GC_INFO_SET_PURPLE(v) \ 61 do {(v) = (v) | GC_COLOR;} while (0) 62 63 typedef struct _gc_root_buffer { 64 zend_refcounted *ref; 65 struct _gc_root_buffer *next; /* double-linked list */ 66 struct _gc_root_buffer *prev; 67 uint32_t refcount; 68 } gc_root_buffer; 69 70 #define GC_NUM_ADDITIONAL_ENTRIES \ 71 ((4096 - ZEND_MM_OVERHEAD - sizeof(void*) * 2) / sizeof(gc_root_buffer)) 72 73 typedef struct _gc_additional_bufer gc_additional_buffer; 74 75 struct _gc_additional_bufer { 76 uint32_t used; 77 gc_additional_buffer *next; 78 gc_root_buffer buf[GC_NUM_ADDITIONAL_ENTRIES]; 79 }; 80 81 typedef struct _zend_gc_globals { 82 zend_bool gc_enabled; 83 zend_bool gc_active; 84 zend_bool gc_full; 85 86 gc_root_buffer *buf; /* preallocated arrays of buffers */ 87 gc_root_buffer roots; /* list of possible roots of cycles */ 88 gc_root_buffer *unused; /* list of unused buffers */ 89 gc_root_buffer *first_unused; /* pointer to first unused buffer */ 90 gc_root_buffer *last_unused; /* pointer to last unused buffer */ 91 92 gc_root_buffer to_free; /* list to free */ 93 gc_root_buffer *next_to_free; 94 95 uint32_t gc_runs; 96 uint32_t collected; 97 98 #if GC_BENCH 99 uint32_t root_buf_length; 100 uint32_t root_buf_peak; 101 uint32_t zval_possible_root; 102 uint32_t zval_buffered; 103 uint32_t zval_remove_from_buffer; 104 uint32_t zval_marked_grey; 105 #endif 106 107 gc_additional_buffer *additional_buffer; 108 109 } zend_gc_globals; 110 111 #ifdef ZTS 112 BEGIN_EXTERN_C() 113 ZEND_API extern int gc_globals_id; 114 END_EXTERN_C() 115 #define GC_G(v) ZEND_TSRMG(gc_globals_id, zend_gc_globals *, v) 116 #else 117 #define GC_G(v) (gc_globals.v) 118 extern ZEND_API zend_gc_globals gc_globals; 119 #endif 120 121 BEGIN_EXTERN_C() 122 ZEND_API extern int (*gc_collect_cycles)(void); 123 124 ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref); 125 ZEND_API void ZEND_FASTCALL gc_remove_from_buffer(zend_refcounted *ref); 126 ZEND_API void gc_globals_ctor(void); 127 ZEND_API void gc_globals_dtor(void); 128 ZEND_API void gc_init(void); 129 ZEND_API void gc_reset(void); 130 131 /* The default implementation of the gc_collect_cycles callback. */ 132 ZEND_API int zend_gc_collect_cycles(void); END_EXTERN_C()133END_EXTERN_C() 134 135 #define GC_ZVAL_CHECK_POSSIBLE_ROOT(z) \ 136 gc_check_possible_root((z)) 137 138 #define GC_REMOVE_FROM_BUFFER(p) do { \ 139 zend_refcounted *_p = (zend_refcounted*)(p); \ 140 if (GC_ADDRESS(GC_INFO(_p))) { \ 141 gc_remove_from_buffer(_p); \ 142 } \ 143 } while (0) 144 145 static zend_always_inline void gc_check_possible_root(zval *z) 146 { 147 ZVAL_DEREF(z); 148 if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) { 149 gc_possible_root(Z_COUNTED_P(z)); 150 } 151 } 152 153 #endif /* ZEND_GC_H */ 154 155 /* 156 * Local variables: 157 * tab-width: 4 158 * c-basic-offset: 4 159 * indent-tabs-mode: t 160 * End: 161 */ 162