zend_gc.h 7.2 KB

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