PageRenderTime 55ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/mono/metadata/sgen-gc.h

https://bitbucket.org/danipen/mono
C Header | 1034 lines | 716 code | 180 blank | 138 comment | 66 complexity | 8f95323efd54f478685d066afdc8c19a MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. /*
  2. * sgen-gc.c: Simple generational GC.
  3. *
  4. * Copyright 2001-2003 Ximian, Inc
  5. * Copyright 2003-2010 Novell, Inc.
  6. * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
  7. * Copyright (C) 2012 Xamarin Inc
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Library General Public
  11. * License 2.0 as published by the Free Software Foundation;
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Library General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Library General Public
  19. * License 2.0 along with this library; if not, write to the Free
  20. * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22. #ifndef __MONO_SGENGC_H__
  23. #define __MONO_SGENGC_H__
  24. /* pthread impl */
  25. #include "config.h"
  26. #ifdef HAVE_SGEN_GC
  27. typedef struct _SgenThreadInfo SgenThreadInfo;
  28. #define THREAD_INFO_TYPE SgenThreadInfo
  29. #include <glib.h>
  30. #ifdef HAVE_PTHREAD_H
  31. #include <pthread.h>
  32. #endif
  33. #include <signal.h>
  34. #include <mono/utils/mono-compiler.h>
  35. #include <mono/utils/mono-threads.h>
  36. #include <mono/utils/dtrace.h>
  37. #include <mono/utils/mono-logger-internal.h>
  38. #include <mono/io-layer/mono-mutex.h>
  39. #include <mono/metadata/class-internals.h>
  40. #include <mono/metadata/object-internals.h>
  41. #include <mono/metadata/sgen-conf.h>
  42. #include <mono/metadata/sgen-archdep.h>
  43. #include <mono/metadata/sgen-descriptor.h>
  44. #include <mono/metadata/sgen-gray.h>
  45. #include <mono/metadata/sgen-hash-table.h>
  46. /* The method used to clear the nursery */
  47. /* Clearing at nursery collections is the safest, but has bad interactions with caches.
  48. * Clearing at TLAB creation is much faster, but more complex and it might expose hard
  49. * to find bugs.
  50. */
  51. typedef enum {
  52. CLEAR_AT_GC,
  53. CLEAR_AT_TLAB_CREATION
  54. } NurseryClearPolicy;
  55. NurseryClearPolicy sgen_get_nursery_clear_policy (void) MONO_INTERNAL;
  56. #define SGEN_TV_DECLARE(name) gint64 name
  57. #define SGEN_TV_GETTIME(tv) tv = mono_100ns_ticks ()
  58. #define SGEN_TV_ELAPSED(start,end) (int)((end-start) / 10)
  59. #define SGEN_TV_ELAPSED_MS(start,end) ((SGEN_TV_ELAPSED((start),(end)) + 500) / 1000)
  60. /* eventually share with MonoThread? */
  61. /*
  62. * This structure extends the MonoThreadInfo structure.
  63. */
  64. struct _SgenThreadInfo {
  65. MonoThreadInfo info;
  66. int skip;
  67. volatile int in_critical_region;
  68. gboolean joined_stw;
  69. gboolean doing_handshake;
  70. gboolean thread_is_dying;
  71. gboolean gc_disabled;
  72. void *stack_end;
  73. void *stack_start;
  74. void *stack_start_limit;
  75. char **tlab_next_addr;
  76. char **tlab_start_addr;
  77. char **tlab_temp_end_addr;
  78. char **tlab_real_end_addr;
  79. gpointer runtime_data;
  80. /* Only used on POSIX platforms */
  81. int signal;
  82. /* Ditto */
  83. unsigned int stop_count; /* to catch duplicate signals */
  84. gpointer stopped_ip; /* only valid if the thread is stopped */
  85. MonoDomain *stopped_domain; /* ditto */
  86. #ifdef USE_MONO_CTX
  87. MonoContext ctx; /* ditto */
  88. #else
  89. gpointer regs[ARCH_NUM_REGS]; /* ditto */
  90. #endif
  91. #ifndef HAVE_KW_THREAD
  92. char *tlab_start;
  93. char *tlab_next;
  94. char *tlab_temp_end;
  95. char *tlab_real_end;
  96. #endif
  97. };
  98. /*
  99. * The nursery section uses this struct.
  100. */
  101. typedef struct _GCMemSection GCMemSection;
  102. struct _GCMemSection {
  103. char *data;
  104. mword size;
  105. /* pointer where more data could be allocated if it fits */
  106. char *next_data;
  107. char *end_data;
  108. /*
  109. * scan starts is an array of pointers to objects equally spaced in the allocation area
  110. * They let use quickly find pinned objects from pinning pointers.
  111. */
  112. char **scan_starts;
  113. /* in major collections indexes in the pin_queue for objects that pin this section */
  114. void **pin_queue_start;
  115. int pin_queue_num_entries;
  116. unsigned short num_scan_start;
  117. };
  118. /*
  119. * Recursion is not allowed for the thread lock.
  120. */
  121. #define LOCK_DECLARE(name) mono_mutex_t name
  122. /* if changing LOCK_INIT to something that isn't idempotent, look at
  123. its use in mono_gc_base_init in sgen-gc.c */
  124. #define LOCK_INIT(name) mono_mutex_init (&(name), NULL)
  125. #define LOCK_GC do { \
  126. mono_mutex_lock (&gc_mutex); \
  127. MONO_GC_LOCKED (); \
  128. } while (0)
  129. #define TRYLOCK_GC (mono_mutex_trylock (&gc_mutex) == 0)
  130. #define UNLOCK_GC do { \
  131. mono_mutex_unlock (&gc_mutex); \
  132. MONO_GC_UNLOCKED (); \
  133. } while (0)
  134. extern LOCK_DECLARE (sgen_interruption_mutex);
  135. #define LOCK_INTERRUPTION mono_mutex_lock (&sgen_interruption_mutex)
  136. #define UNLOCK_INTERRUPTION mono_mutex_unlock (&sgen_interruption_mutex)
  137. /* FIXME: Use InterlockedAdd & InterlockedAdd64 to reduce the CAS cost. */
  138. #define SGEN_CAS_PTR InterlockedCompareExchangePointer
  139. #define SGEN_ATOMIC_ADD(x,i) do { \
  140. int __old_x; \
  141. do { \
  142. __old_x = (x); \
  143. } while (InterlockedCompareExchange (&(x), __old_x + (i), __old_x) != __old_x); \
  144. } while (0)
  145. #define SGEN_ATOMIC_ADD_P(x,i) do { \
  146. size_t __old_x; \
  147. do { \
  148. __old_x = (x); \
  149. } while (InterlockedCompareExchangePointer ((void**)&(x), (void*)(__old_x + (i)), (void*)__old_x) != (void*)__old_x); \
  150. } while (0)
  151. #ifndef HOST_WIN32
  152. /* we intercept pthread_create calls to know which threads exist */
  153. #define USE_PTHREAD_INTERCEPT 1
  154. #endif
  155. #ifdef HEAVY_STATISTICS
  156. #define HEAVY_STAT(x) x
  157. extern long long stat_objects_alloced_degraded;
  158. extern long long stat_bytes_alloced_degraded;
  159. extern long long stat_copy_object_called_major;
  160. extern long long stat_objects_copied_major;
  161. #else
  162. #define HEAVY_STAT(x)
  163. #endif
  164. #define SGEN_ASSERT(level, a, ...) do { \
  165. if (G_UNLIKELY ((level) <= SGEN_MAX_ASSERT_LEVEL && !(a))) { \
  166. g_error (__VA_ARGS__); \
  167. } } while (0)
  168. #define SGEN_LOG(level, format, ...) do { \
  169. if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) { \
  170. mono_gc_printf (gc_debug_file, format, ##__VA_ARGS__); \
  171. } } while (0)
  172. #define SGEN_COND_LOG(level, cond, format, ...) do { \
  173. if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) { \
  174. if (cond) \
  175. mono_gc_printf (gc_debug_file, format, ##__VA_ARGS__); \
  176. } } while (0)
  177. #define SGEN_LOG_DO(level, fun) do { \
  178. if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) { \
  179. fun; \
  180. } } while (0)
  181. extern int gc_debug_level;
  182. extern FILE* gc_debug_file;
  183. extern int current_collection_generation;
  184. extern unsigned int sgen_global_stop_count;
  185. extern gboolean bridge_processing_in_progress;
  186. extern int num_ready_finalizers;
  187. #define SGEN_ALLOC_ALIGN 8
  188. #define SGEN_ALLOC_ALIGN_BITS 3
  189. #define SGEN_ALIGN_UP(s) (((s)+(SGEN_ALLOC_ALIGN-1)) & ~(SGEN_ALLOC_ALIGN-1))
  190. /*
  191. * The link pointer is hidden by negating each bit. We use the lowest
  192. * bit of the link (before negation) to store whether it needs
  193. * resurrection tracking.
  194. */
  195. #define HIDE_POINTER(p,t) ((gpointer)(~((gulong)(p)|((t)?1:0))))
  196. #define REVEAL_POINTER(p) ((gpointer)((~(gulong)(p))&~3L))
  197. #ifdef SGEN_ALIGN_NURSERY
  198. #define SGEN_PTR_IN_NURSERY(p,bits,start,end) (((mword)(p) & ~((1 << (bits)) - 1)) == (mword)(start))
  199. #else
  200. #define SGEN_PTR_IN_NURSERY(p,bits,start,end) ((char*)(p) >= (start) && (char*)(p) < (end))
  201. #endif
  202. #ifdef USER_CONFIG
  203. /* good sizes are 512KB-1MB: larger ones increase a lot memzeroing time */
  204. #define DEFAULT_NURSERY_SIZE (sgen_nursery_size)
  205. extern int sgen_nursery_size MONO_INTERNAL;
  206. #ifdef SGEN_ALIGN_NURSERY
  207. /* The number of trailing 0 bits in DEFAULT_NURSERY_SIZE */
  208. #define DEFAULT_NURSERY_BITS (sgen_nursery_bits)
  209. extern int sgen_nursery_bits MONO_INTERNAL;
  210. #endif
  211. #else
  212. #define DEFAULT_NURSERY_SIZE (4*1024*1024)
  213. #ifdef SGEN_ALIGN_NURSERY
  214. #define DEFAULT_NURSERY_BITS 22
  215. #endif
  216. #endif
  217. #ifndef SGEN_ALIGN_NURSERY
  218. #define DEFAULT_NURSERY_BITS -1
  219. #endif
  220. extern char *sgen_nursery_start MONO_INTERNAL;
  221. extern char *sgen_nursery_end MONO_INTERNAL;
  222. static inline gboolean
  223. sgen_ptr_in_nursery (void *p)
  224. {
  225. return SGEN_PTR_IN_NURSERY ((p), DEFAULT_NURSERY_BITS, sgen_nursery_start, sgen_nursery_end);
  226. }
  227. static inline char*
  228. sgen_get_nursery_start (void)
  229. {
  230. return sgen_nursery_start;
  231. }
  232. static inline char*
  233. sgen_get_nursery_end (void)
  234. {
  235. return sgen_nursery_end;
  236. }
  237. /* Structure that corresponds to a MonoVTable: desc is a mword so requires
  238. * no cast from a pointer to an integer
  239. */
  240. typedef struct {
  241. MonoClass *klass;
  242. mword desc;
  243. } GCVTable;
  244. /* these bits are set in the object vtable: we could merge them since an object can be
  245. * either pinned or forwarded but not both.
  246. * We store them in the vtable slot because the bits are used in the sync block for
  247. * other purposes: if we merge them and alloc the sync blocks aligned to 8 bytes, we can change
  248. * this and use bit 3 in the syncblock (with the lower two bits both set for forwarded, that
  249. * would be an invalid combination for the monitor and hash code).
  250. * The values are already shifted.
  251. * The forwarding address is stored in the sync block.
  252. */
  253. #define SGEN_FORWARDED_BIT 1
  254. #define SGEN_PINNED_BIT 2
  255. #define SGEN_VTABLE_BITS_MASK 0x3
  256. /* returns NULL if not forwarded, or the forwarded address */
  257. #define SGEN_OBJECT_IS_FORWARDED(obj) (((mword*)(obj))[0] & SGEN_FORWARDED_BIT ? (void*)(((mword*)(obj))[0] & ~SGEN_VTABLE_BITS_MASK) : NULL)
  258. #define SGEN_OBJECT_IS_PINNED(obj) (((mword*)(obj))[0] & SGEN_PINNED_BIT)
  259. /* set the forwarded address fw_addr for object obj */
  260. #define SGEN_FORWARD_OBJECT(obj,fw_addr) do { \
  261. ((mword*)(obj))[0] = (mword)(fw_addr) | SGEN_FORWARDED_BIT; \
  262. } while (0)
  263. #define SGEN_PIN_OBJECT(obj) do { \
  264. ((mword*)(obj))[0] |= SGEN_PINNED_BIT; \
  265. } while (0)
  266. #define SGEN_UNPIN_OBJECT(obj) do { \
  267. ((mword*)(obj))[0] &= ~SGEN_PINNED_BIT; \
  268. } while (0)
  269. /*
  270. * Since we set bits in the vtable, use the macro to load it from the pointer to
  271. * an object that is potentially pinned.
  272. */
  273. #define SGEN_LOAD_VTABLE(addr) ((*(mword*)(addr)) & ~SGEN_VTABLE_BITS_MASK)
  274. #if defined(SGEN_GRAY_OBJECT_ENQUEUE) || SGEN_MAX_DEBUG_LEVEL >= 9
  275. #define GRAY_OBJECT_ENQUEUE sgen_gray_object_enqueue
  276. #define GRAY_OBJECT_DEQUEUE(queue,o) ((o) = sgen_gray_object_dequeue ((queue)))
  277. #else
  278. #define GRAY_OBJECT_ENQUEUE(queue,o) do { \
  279. if (G_UNLIKELY (!(queue)->first || (queue)->first->end == SGEN_GRAY_QUEUE_SECTION_SIZE)) \
  280. sgen_gray_object_enqueue ((queue), (o)); \
  281. else \
  282. (queue)->first->objects [(queue)->first->end++] = (o); \
  283. PREFETCH ((o)); \
  284. } while (0)
  285. #define GRAY_OBJECT_DEQUEUE(queue,o) do { \
  286. if (!(queue)->first) \
  287. (o) = NULL; \
  288. else if (G_UNLIKELY ((queue)->first->end == 1)) \
  289. (o) = sgen_gray_object_dequeue ((queue)); \
  290. else \
  291. (o) = (queue)->first->objects [--(queue)->first->end]; \
  292. } while (0)
  293. #endif
  294. /*
  295. List of what each bit on of the vtable gc bits means.
  296. */
  297. enum {
  298. SGEN_GC_BIT_BRIDGE_OBJECT = 1,
  299. };
  300. /* the runtime can register areas of memory as roots: we keep two lists of roots,
  301. * a pinned root set for conservatively scanned roots and a normal one for
  302. * precisely scanned roots (currently implemented as a single list).
  303. */
  304. typedef struct _RootRecord RootRecord;
  305. struct _RootRecord {
  306. char *end_root;
  307. mword root_desc;
  308. };
  309. enum {
  310. ROOT_TYPE_NORMAL = 0, /* "normal" roots */
  311. ROOT_TYPE_PINNED = 1, /* roots without a GC descriptor */
  312. ROOT_TYPE_WBARRIER = 2, /* roots with a write barrier */
  313. ROOT_TYPE_NUM
  314. };
  315. extern SgenHashTable roots_hash [ROOT_TYPE_NUM];
  316. typedef void (*IterateObjectCallbackFunc) (char*, size_t, void*);
  317. int sgen_thread_handshake (BOOL suspend) MONO_INTERNAL;
  318. gboolean sgen_suspend_thread (SgenThreadInfo *info) MONO_INTERNAL;
  319. gboolean sgen_resume_thread (SgenThreadInfo *info) MONO_INTERNAL;
  320. void sgen_wait_for_suspend_ack (int count) MONO_INTERNAL;
  321. gboolean sgen_park_current_thread_if_doing_handshake (SgenThreadInfo *p) MONO_INTERNAL;
  322. void sgen_os_init (void) MONO_INTERNAL;
  323. gboolean sgen_is_worker_thread (MonoNativeThreadId thread) MONO_INTERNAL;
  324. void sgen_update_heap_boundaries (mword low, mword high) MONO_INTERNAL;
  325. void sgen_scan_area_with_callback (char *start, char *end, IterateObjectCallbackFunc callback, void *data, gboolean allow_flags) MONO_INTERNAL;
  326. void sgen_check_section_scan_starts (GCMemSection *section) MONO_INTERNAL;
  327. /* Keep in sync with description_for_type() in sgen-internal.c! */
  328. enum {
  329. INTERNAL_MEM_PIN_QUEUE,
  330. INTERNAL_MEM_FRAGMENT,
  331. INTERNAL_MEM_SECTION,
  332. INTERNAL_MEM_SCAN_STARTS,
  333. INTERNAL_MEM_FIN_TABLE,
  334. INTERNAL_MEM_FINALIZE_ENTRY,
  335. INTERNAL_MEM_FINALIZE_READY_ENTRY,
  336. INTERNAL_MEM_DISLINK_TABLE,
  337. INTERNAL_MEM_DISLINK,
  338. INTERNAL_MEM_ROOTS_TABLE,
  339. INTERNAL_MEM_ROOT_RECORD,
  340. INTERNAL_MEM_STATISTICS,
  341. INTERNAL_MEM_STAT_PINNED_CLASS,
  342. INTERNAL_MEM_STAT_REMSET_CLASS,
  343. INTERNAL_MEM_GRAY_QUEUE,
  344. INTERNAL_MEM_MS_TABLES,
  345. INTERNAL_MEM_MS_BLOCK_INFO,
  346. INTERNAL_MEM_EPHEMERON_LINK,
  347. INTERNAL_MEM_WORKER_DATA,
  348. INTERNAL_MEM_WORKER_JOB_DATA,
  349. INTERNAL_MEM_BRIDGE_DATA,
  350. INTERNAL_MEM_BRIDGE_HASH_TABLE,
  351. INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY,
  352. INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE,
  353. INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE_ENTRY,
  354. INTERNAL_MEM_JOB_QUEUE_ENTRY,
  355. INTERNAL_MEM_TOGGLEREF_DATA,
  356. INTERNAL_MEM_CARDTABLE_MOD_UNION,
  357. INTERNAL_MEM_MAX
  358. };
  359. enum {
  360. GENERATION_NURSERY,
  361. GENERATION_OLD,
  362. GENERATION_MAX
  363. };
  364. #ifdef SGEN_BINARY_PROTOCOL
  365. #define BINARY_PROTOCOL_ARG(x) ,x
  366. #else
  367. #define BINARY_PROTOCOL_ARG(x)
  368. #endif
  369. void sgen_init_internal_allocator (void) MONO_INTERNAL;
  370. typedef struct _ObjectList ObjectList;
  371. struct _ObjectList {
  372. MonoObject *obj;
  373. ObjectList *next;
  374. };
  375. typedef void (*CopyOrMarkObjectFunc) (void**, SgenGrayQueue*);
  376. typedef void (*ScanObjectFunc) (char*, SgenGrayQueue*);
  377. typedef void (*ScanVTypeFunc) (char*, mword desc, SgenGrayQueue* BINARY_PROTOCOL_ARG (size_t size));
  378. typedef struct
  379. {
  380. ScanObjectFunc scan_func;
  381. CopyOrMarkObjectFunc copy_func;
  382. SgenGrayQueue *queue;
  383. } ScanCopyContext;
  384. void sgen_report_internal_mem_usage (void) MONO_INTERNAL;
  385. void sgen_dump_internal_mem_usage (FILE *heap_dump_file) MONO_INTERNAL;
  386. void sgen_dump_section (GCMemSection *section, const char *type) MONO_INTERNAL;
  387. void sgen_dump_occupied (char *start, char *end, char *section_start) MONO_INTERNAL;
  388. void sgen_register_moved_object (void *obj, void *destination) MONO_INTERNAL;
  389. void sgen_register_fixed_internal_mem_type (int type, size_t size) MONO_INTERNAL;
  390. void* sgen_alloc_internal (int type) MONO_INTERNAL;
  391. void sgen_free_internal (void *addr, int type) MONO_INTERNAL;
  392. void* sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure) MONO_INTERNAL;
  393. void sgen_free_internal_dynamic (void *addr, size_t size, int type) MONO_INTERNAL;
  394. void** sgen_find_optimized_pin_queue_area (void *start, void *end, int *num) MONO_INTERNAL;
  395. void sgen_find_section_pin_queue_start_end (GCMemSection *section) MONO_INTERNAL;
  396. void sgen_pin_objects_in_section (GCMemSection *section, ScanCopyContext ctx) MONO_INTERNAL;
  397. void sgen_pin_stats_register_object (char *obj, size_t size);
  398. void sgen_pin_stats_register_global_remset (char *obj);
  399. void sgen_pin_stats_print_class_stats (void);
  400. void sgen_sort_addresses (void **array, int size) MONO_INTERNAL;
  401. void sgen_add_to_global_remset (gpointer ptr, gpointer obj) MONO_INTERNAL;
  402. int sgen_get_current_collection_generation (void) MONO_INTERNAL;
  403. gboolean sgen_collection_is_parallel (void) MONO_INTERNAL;
  404. gboolean sgen_collection_is_concurrent (void) MONO_INTERNAL;
  405. gboolean sgen_concurrent_collection_in_progress (void) MONO_INTERNAL;
  406. typedef struct {
  407. CopyOrMarkObjectFunc copy_or_mark_object;
  408. ScanObjectFunc scan_object;
  409. ScanVTypeFunc scan_vtype;
  410. /*FIXME add allocation function? */
  411. } SgenObjectOperations;
  412. SgenObjectOperations *sgen_get_current_object_ops (void) MONO_INTERNAL;
  413. typedef struct _SgenFragment SgenFragment;
  414. struct _SgenFragment {
  415. SgenFragment *next;
  416. char *fragment_start;
  417. char *fragment_next; /* the current soft limit for allocation */
  418. char *fragment_end;
  419. SgenFragment *next_in_order; /* We use a different entry for all active fragments so we can avoid SMR. */
  420. };
  421. typedef struct {
  422. SgenFragment *alloc_head; /* List head to be used when allocating memory. Walk with fragment_next. */
  423. SgenFragment *region_head; /* List head of the region used by this allocator. Walk with next_in_order. */
  424. } SgenFragmentAllocator;
  425. void sgen_fragment_allocator_add (SgenFragmentAllocator *allocator, char *start, char *end) MONO_INTERNAL;
  426. void sgen_fragment_allocator_release (SgenFragmentAllocator *allocator) MONO_INTERNAL;
  427. void* sgen_fragment_allocator_serial_alloc (SgenFragmentAllocator *allocator, size_t size) MONO_INTERNAL;
  428. void* sgen_fragment_allocator_par_alloc (SgenFragmentAllocator *allocator, size_t size) MONO_INTERNAL;
  429. void* sgen_fragment_allocator_serial_range_alloc (SgenFragmentAllocator *allocator, size_t desired_size, size_t minimum_size, size_t *out_alloc_size) MONO_INTERNAL;
  430. void* sgen_fragment_allocator_par_range_alloc (SgenFragmentAllocator *allocator, size_t desired_size, size_t minimum_size, size_t *out_alloc_size) MONO_INTERNAL;
  431. SgenFragment* sgen_fragment_allocator_alloc (void) MONO_INTERNAL;
  432. void sgen_clear_allocator_fragments (SgenFragmentAllocator *allocator) MONO_INTERNAL;
  433. void sgen_clear_range (char *start, char *end) MONO_INTERNAL;
  434. /*
  435. This is a space/speed compromise as we need to make sure the from/to space check is both O(1)
  436. and only hit cache hot memory. On a 4Mb nursery it requires 1024 bytes, or 3% of your average
  437. L1 cache. On small configs with a 512kb nursery, this goes to 0.4%.
  438. Experimental results on how much space we waste with a 4Mb nursery:
  439. Note that the wastage applies to the half nursery, or 2Mb:
  440. Test 1 (compiling corlib):
  441. 9: avg: 3.1k
  442. 8: avg: 1.6k
  443. */
  444. #define SGEN_TO_SPACE_GRANULE_BITS 9
  445. #define SGEN_TO_SPACE_GRANULE_IN_BYTES (1 << SGEN_TO_SPACE_GRANULE_BITS)
  446. extern char *sgen_space_bitmap MONO_INTERNAL;
  447. extern int sgen_space_bitmap_size MONO_INTERNAL;
  448. static inline gboolean
  449. sgen_nursery_is_to_space (char *object)
  450. {
  451. int idx = (object - sgen_nursery_start) >> SGEN_TO_SPACE_GRANULE_BITS;
  452. int byte = idx / 8;
  453. int bit = idx & 0x7;
  454. SGEN_ASSERT (4, sgen_ptr_in_nursery (object), "object %p is not in nursery [%p - %p]", object, sgen_get_nursery_start (), sgen_get_nursery_end ());
  455. SGEN_ASSERT (4, byte < sgen_space_bitmap_size, "byte index %d out of range", byte, sgen_space_bitmap_size);
  456. return (sgen_space_bitmap [byte] & (1 << bit)) != 0;
  457. }
  458. static inline gboolean
  459. sgen_nursery_is_from_space (char *object)
  460. {
  461. return !sgen_nursery_is_to_space (object);
  462. }
  463. static inline gboolean
  464. sgen_nursery_is_object_alive (char *obj)
  465. {
  466. /* FIXME put this asserts under a non default level */
  467. g_assert (sgen_ptr_in_nursery (obj));
  468. if (sgen_nursery_is_to_space (obj))
  469. return TRUE;
  470. if (SGEN_OBJECT_IS_PINNED (obj) || SGEN_OBJECT_IS_FORWARDED (obj))
  471. return TRUE;
  472. return FALSE;
  473. }
  474. typedef struct {
  475. gboolean is_split;
  476. char* (*alloc_for_promotion) (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references);
  477. char* (*par_alloc_for_promotion) (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references);
  478. SgenObjectOperations serial_ops;
  479. SgenObjectOperations parallel_ops;
  480. void (*prepare_to_space) (char *to_space_bitmap, int space_bitmap_size);
  481. void (*clear_fragments) (void);
  482. SgenFragment* (*build_fragments_get_exclude_head) (void);
  483. void (*build_fragments_release_exclude_head) (void);
  484. void (*build_fragments_finish) (SgenFragmentAllocator *allocator);
  485. void (*init_nursery) (SgenFragmentAllocator *allocator, char *start, char *end);
  486. gboolean (*handle_gc_param) (const char *opt); /* Optional */
  487. void (*print_gc_param_usage) (void); /* Optional */
  488. } SgenMinorCollector;
  489. extern SgenMinorCollector sgen_minor_collector;
  490. void sgen_simple_nursery_init (SgenMinorCollector *collector) MONO_INTERNAL;
  491. void sgen_split_nursery_init (SgenMinorCollector *collector) MONO_INTERNAL;
  492. typedef void (*sgen_cardtable_block_callback) (mword start, mword size);
  493. void sgen_major_collector_iterate_live_block_ranges (sgen_cardtable_block_callback callback) MONO_INTERNAL;
  494. typedef struct _SgenMajorCollector SgenMajorCollector;
  495. struct _SgenMajorCollector {
  496. size_t section_size;
  497. gboolean is_parallel;
  498. gboolean is_concurrent;
  499. gboolean supports_cardtable;
  500. gboolean sweeps_lazily;
  501. /*
  502. * This is set to TRUE if the sweep for the last major
  503. * collection has been completed.
  504. */
  505. gboolean *have_swept;
  506. /*
  507. * This is set to TRUE by the sweep if the next major
  508. * collection should be synchronous (for evacuation). For
  509. * non-concurrent collectors, this should be NULL.
  510. */
  511. gboolean *want_synchronous_collection;
  512. void* (*alloc_heap) (mword nursery_size, mword nursery_align, int nursery_bits);
  513. gboolean (*is_object_live) (char *obj);
  514. void* (*alloc_small_pinned_obj) (MonoVTable *vtable, size_t size, gboolean has_references);
  515. void* (*alloc_degraded) (MonoVTable *vtable, size_t size);
  516. SgenObjectOperations major_ops;
  517. SgenObjectOperations major_concurrent_ops;
  518. void* (*alloc_object) (MonoVTable *vtable, int size, gboolean has_references);
  519. void* (*par_alloc_object) (MonoVTable *vtable, int size, gboolean has_references);
  520. void (*free_pinned_object) (char *obj, size_t size);
  521. void (*iterate_objects) (gboolean non_pinned, gboolean pinned, IterateObjectCallbackFunc callback, void *data);
  522. void (*free_non_pinned_object) (char *obj, size_t size);
  523. void (*find_pin_queue_start_ends) (SgenGrayQueue *queue);
  524. void (*pin_objects) (SgenGrayQueue *queue);
  525. void (*pin_major_object) (char *obj, SgenGrayQueue *queue);
  526. void (*scan_card_table) (gboolean mod_union, SgenGrayQueue *queue);
  527. void (*iterate_live_block_ranges) (sgen_cardtable_block_callback callback);
  528. void (*update_cardtable_mod_union) (void);
  529. void (*init_to_space) (void);
  530. void (*sweep) (void);
  531. void (*check_scan_starts) (void);
  532. void (*dump_heap) (FILE *heap_dump_file);
  533. gint64 (*get_used_size) (void);
  534. void (*start_nursery_collection) (void);
  535. void (*finish_nursery_collection) (void);
  536. void (*start_major_collection) (void);
  537. void (*finish_major_collection) (void);
  538. void (*have_computed_minor_collection_allowance) (void);
  539. gboolean (*ptr_is_in_non_pinned_space) (char *ptr, char **start);
  540. gboolean (*obj_is_from_pinned_alloc) (char *obj);
  541. void (*report_pinned_memory_usage) (void);
  542. int (*get_num_major_sections) (void);
  543. gboolean (*handle_gc_param) (const char *opt);
  544. void (*print_gc_param_usage) (void);
  545. gboolean (*is_worker_thread) (MonoNativeThreadId thread);
  546. void (*post_param_init) (SgenMajorCollector *collector);
  547. void* (*alloc_worker_data) (void);
  548. void (*init_worker_thread) (void *data);
  549. void (*reset_worker_data) (void *data);
  550. gboolean (*is_valid_object) (char *object);
  551. gboolean (*describe_pointer) (char *pointer);
  552. long long (*get_and_reset_num_major_objects_marked) (void);
  553. };
  554. extern SgenMajorCollector major_collector;
  555. void sgen_marksweep_init (SgenMajorCollector *collector) MONO_INTERNAL;
  556. void sgen_marksweep_fixed_init (SgenMajorCollector *collector) MONO_INTERNAL;
  557. void sgen_marksweep_par_init (SgenMajorCollector *collector) MONO_INTERNAL;
  558. void sgen_marksweep_fixed_par_init (SgenMajorCollector *collector) MONO_INTERNAL;
  559. void sgen_marksweep_conc_init (SgenMajorCollector *collector) MONO_INTERNAL;
  560. SgenMajorCollector* sgen_get_major_collector (void) MONO_INTERNAL;
  561. typedef struct {
  562. void (*wbarrier_set_field) (MonoObject *obj, gpointer field_ptr, MonoObject* value);
  563. void (*wbarrier_set_arrayref) (MonoArray *arr, gpointer slot_ptr, MonoObject* value);
  564. void (*wbarrier_arrayref_copy) (gpointer dest_ptr, gpointer src_ptr, int count);
  565. void (*wbarrier_value_copy) (gpointer dest, gpointer src, int count, MonoClass *klass);
  566. void (*wbarrier_object_copy) (MonoObject* obj, MonoObject *src);
  567. void (*wbarrier_generic_nostore) (gpointer ptr);
  568. void (*record_pointer) (gpointer ptr);
  569. void (*finish_scan_remsets) (void *start_nursery, void *end_nursery, SgenGrayQueue *queue);
  570. void (*prepare_for_major_collection) (void);
  571. void (*finish_minor_collection) (void);
  572. gboolean (*find_address) (char *addr);
  573. } SgenRemeberedSet;
  574. SgenRemeberedSet *sgen_get_remset (void) MONO_INTERNAL;
  575. static guint /*__attribute__((noinline)) not sure if this hint is a good idea*/
  576. slow_object_get_size (MonoVTable *vtable, MonoObject* o)
  577. {
  578. MonoClass *klass = vtable->klass;
  579. /*
  580. * We depend on mono_string_length_fast and
  581. * mono_array_length_fast not using the object's vtable.
  582. */
  583. if (klass == mono_defaults.string_class) {
  584. return sizeof (MonoString) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
  585. } else if (klass->rank) {
  586. MonoArray *array = (MonoArray*)o;
  587. size_t size = sizeof (MonoArray) + klass->sizes.element_size * mono_array_length_fast (array);
  588. if (G_UNLIKELY (array->bounds)) {
  589. size += sizeof (mono_array_size_t) - 1;
  590. size &= ~(sizeof (mono_array_size_t) - 1);
  591. size += sizeof (MonoArrayBounds) * klass->rank;
  592. }
  593. return size;
  594. } else {
  595. /* from a created object: the class must be inited already */
  596. return klass->instance_size;
  597. }
  598. }
  599. /*
  600. * This function can be called on an object whose first word, the
  601. * vtable field, is not intact. This is necessary for the parallel
  602. * collector.
  603. */
  604. static inline guint
  605. sgen_par_object_get_size (MonoVTable *vtable, MonoObject* o)
  606. {
  607. mword descr = (mword)vtable->gc_descr;
  608. mword type = descr & 0x7;
  609. if (type == DESC_TYPE_RUN_LENGTH || type == DESC_TYPE_SMALL_BITMAP) {
  610. mword size = descr & 0xfff8;
  611. if (size == 0) /* This is used to encode a string */
  612. return sizeof (MonoString) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
  613. return size;
  614. } else if (type == DESC_TYPE_VECTOR) {
  615. int element_size = ((descr) >> VECTOR_ELSIZE_SHIFT) & MAX_ELEMENT_SIZE;
  616. MonoArray *array = (MonoArray*)o;
  617. size_t size = sizeof (MonoArray) + element_size * mono_array_length_fast (array);
  618. if (descr & VECTOR_KIND_ARRAY) {
  619. size += sizeof (mono_array_size_t) - 1;
  620. size &= ~(sizeof (mono_array_size_t) - 1);
  621. size += sizeof (MonoArrayBounds) * vtable->klass->rank;
  622. }
  623. return size;
  624. }
  625. return slow_object_get_size (vtable, o);
  626. }
  627. static inline guint
  628. sgen_safe_object_get_size (MonoObject *obj)
  629. {
  630. char *forwarded;
  631. if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj)))
  632. obj = (MonoObject*)forwarded;
  633. return sgen_par_object_get_size ((MonoVTable*)SGEN_LOAD_VTABLE (obj), obj);
  634. }
  635. const char* sgen_safe_name (void* obj) MONO_INTERNAL;
  636. gboolean sgen_object_is_live (void *obj) MONO_INTERNAL;
  637. gboolean sgen_need_bridge_processing (void) MONO_INTERNAL;
  638. void sgen_bridge_reset_data (void) MONO_INTERNAL;
  639. void sgen_bridge_processing_stw_step (void) MONO_INTERNAL;
  640. void sgen_bridge_processing_finish (int generation) MONO_INTERNAL;
  641. void sgen_register_test_bridge_callbacks (const char *bridge_class_name) MONO_INTERNAL;
  642. gboolean sgen_is_bridge_object (MonoObject *obj) MONO_INTERNAL;
  643. gboolean sgen_is_bridge_class (MonoClass *class) MONO_INTERNAL;
  644. void sgen_mark_bridge_object (MonoObject *obj) MONO_INTERNAL;
  645. void sgen_bridge_register_finalized_object (MonoObject *object) MONO_INTERNAL;
  646. void sgen_scan_togglerefs (char *start, char *end, ScanCopyContext ctx) MONO_INTERNAL;
  647. void sgen_process_togglerefs (void) MONO_INTERNAL;
  648. typedef mono_bool (*WeakLinkAlivePredicateFunc) (MonoObject*, void*);
  649. void sgen_null_links_with_predicate (int generation, WeakLinkAlivePredicateFunc predicate, void *data) MONO_INTERNAL;
  650. gboolean sgen_gc_is_object_ready_for_finalization (void *object) MONO_INTERNAL;
  651. void sgen_gc_lock (void) MONO_INTERNAL;
  652. void sgen_gc_unlock (void) MONO_INTERNAL;
  653. void sgen_gc_event_moves (void) MONO_INTERNAL;
  654. void sgen_queue_finalization_entry (MonoObject *obj) MONO_INTERNAL;
  655. const char* sgen_generation_name (int generation) MONO_INTERNAL;
  656. void sgen_collect_bridge_objects (int generation, ScanCopyContext ctx) MONO_INTERNAL;
  657. void sgen_finalize_in_range (int generation, ScanCopyContext ctx) MONO_INTERNAL;
  658. void sgen_null_link_in_range (int generation, gboolean before_finalization, ScanCopyContext ctx) MONO_INTERNAL;
  659. void sgen_null_links_for_domain (MonoDomain *domain, int generation) MONO_INTERNAL;
  660. void sgen_remove_finalizers_for_domain (MonoDomain *domain, int generation) MONO_INTERNAL;
  661. void sgen_process_fin_stage_entries (void) MONO_INTERNAL;
  662. void sgen_process_dislink_stage_entries (void) MONO_INTERNAL;
  663. void sgen_register_disappearing_link (MonoObject *obj, void **link, gboolean track, gboolean in_gc) MONO_INTERNAL;
  664. gboolean sgen_drain_gray_stack (int max_objs, ScanCopyContext ctx) MONO_INTERNAL;
  665. enum {
  666. SPACE_NURSERY,
  667. SPACE_MAJOR,
  668. SPACE_LOS
  669. };
  670. void sgen_pin_object (void *object, SgenGrayQueue *queue) MONO_INTERNAL;
  671. void sgen_parallel_pin_or_update (void **ptr, void *obj, MonoVTable *vt, SgenGrayQueue *queue) MONO_INTERNAL;
  672. void sgen_set_pinned_from_failed_allocation (mword objsize) MONO_INTERNAL;
  673. void sgen_ensure_free_space (size_t size) MONO_INTERNAL;
  674. void sgen_perform_collection (size_t requested_size, int generation_to_collect, const char *reason, gboolean wait_to_finish) MONO_INTERNAL;
  675. gboolean sgen_has_critical_method (void) MONO_INTERNAL;
  676. gboolean sgen_is_critical_method (MonoMethod *method) MONO_INTERNAL;
  677. /* STW */
  678. typedef struct {
  679. int generation;
  680. const char *reason;
  681. gboolean is_overflow;
  682. SGEN_TV_DECLARE (total_time);
  683. SGEN_TV_DECLARE (stw_time);
  684. SGEN_TV_DECLARE (bridge_time);
  685. } GGTimingInfo;
  686. int sgen_stop_world (int generation) MONO_INTERNAL;
  687. int sgen_restart_world (int generation, GGTimingInfo *timing) MONO_INTERNAL;
  688. /* LOS */
  689. typedef struct _LOSObject LOSObject;
  690. struct _LOSObject {
  691. LOSObject *next;
  692. mword size; /* this is the object size, lowest bit used for pin/mark */
  693. guint8 *cardtable_mod_union; /* only used by the concurrent collector */
  694. #if SIZEOF_VOID_P < 8
  695. mword dummy; /* to align object to sizeof (double) */
  696. #endif
  697. char data [MONO_ZERO_LEN_ARRAY];
  698. };
  699. #define ARRAY_OBJ_INDEX(ptr,array,elem_size) (((char*)(ptr) - ((char*)(array) + G_STRUCT_OFFSET (MonoArray, vector))) / (elem_size))
  700. extern LOSObject *los_object_list;
  701. extern mword los_memory_usage;
  702. void sgen_los_free_object (LOSObject *obj) MONO_INTERNAL;
  703. void* sgen_los_alloc_large_inner (MonoVTable *vtable, size_t size) MONO_INTERNAL;
  704. void sgen_los_sweep (void) MONO_INTERNAL;
  705. gboolean sgen_ptr_is_in_los (char *ptr, char **start) MONO_INTERNAL;
  706. void sgen_los_iterate_objects (IterateObjectCallbackFunc cb, void *user_data) MONO_INTERNAL;
  707. void sgen_los_iterate_live_block_ranges (sgen_cardtable_block_callback callback) MONO_INTERNAL;
  708. void sgen_los_scan_card_table (gboolean mod_union, SgenGrayQueue *queue) MONO_INTERNAL;
  709. void sgen_los_update_cardtable_mod_union (void) MONO_INTERNAL;
  710. void sgen_major_collector_scan_card_table (SgenGrayQueue *queue) MONO_INTERNAL;
  711. gboolean sgen_los_is_valid_object (char *object) MONO_INTERNAL;
  712. gboolean mono_sgen_los_describe_pointer (char *ptr) MONO_INTERNAL;
  713. LOSObject* sgen_los_header_for_object (char *data) MONO_INTERNAL;
  714. mword sgen_los_object_size (LOSObject *obj) MONO_INTERNAL;
  715. void sgen_los_pin_object (char *obj) MONO_INTERNAL;
  716. void sgen_los_unpin_object (char *obj) MONO_INTERNAL;
  717. gboolean sgen_los_object_is_pinned (char *obj) MONO_INTERNAL;
  718. /* nursery allocator */
  719. void sgen_clear_nursery_fragments (void) MONO_INTERNAL;
  720. void sgen_nursery_allocator_prepare_for_pinning (void) MONO_INTERNAL;
  721. void sgen_nursery_allocator_set_nursery_bounds (char *nursery_start, char *nursery_end) MONO_INTERNAL;
  722. mword sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, int num_entries, SgenGrayQueue *unpin_queue) MONO_INTERNAL;
  723. void sgen_init_nursery_allocator (void) MONO_INTERNAL;
  724. void sgen_nursery_allocator_init_heavy_stats (void) MONO_INTERNAL;
  725. void sgen_alloc_init_heavy_stats (void) MONO_INTERNAL;
  726. char* sgen_nursery_alloc_get_upper_alloc_bound (void) MONO_INTERNAL;
  727. void* sgen_nursery_alloc (size_t size) MONO_INTERNAL;
  728. void* sgen_nursery_alloc_range (size_t size, size_t min_size, size_t *out_alloc_size) MONO_INTERNAL;
  729. MonoVTable* sgen_get_array_fill_vtable (void) MONO_INTERNAL;
  730. gboolean sgen_can_alloc_size (size_t size) MONO_INTERNAL;
  731. void sgen_nursery_retire_region (void *address, ptrdiff_t size) MONO_INTERNAL;
  732. void sgen_nursery_alloc_prepare_for_minor (void) MONO_INTERNAL;
  733. void sgen_nursery_alloc_prepare_for_major (void) MONO_INTERNAL;
  734. char* sgen_alloc_for_promotion (char *obj, size_t objsize, gboolean has_references) MONO_INTERNAL;
  735. char* sgen_par_alloc_for_promotion (char *obj, size_t objsize, gboolean has_references) MONO_INTERNAL;
  736. /* TLS Data */
  737. extern MonoNativeTlsKey thread_info_key;
  738. #ifdef HAVE_KW_THREAD
  739. extern __thread SgenThreadInfo *sgen_thread_info;
  740. extern __thread char *stack_end;
  741. #endif
  742. #ifdef HAVE_KW_THREAD
  743. #define TLAB_ACCESS_INIT
  744. #define IN_CRITICAL_REGION sgen_thread_info->in_critical_region
  745. #else
  746. #define TLAB_ACCESS_INIT SgenThreadInfo *__thread_info__ = mono_native_tls_get_value (thread_info_key)
  747. #define IN_CRITICAL_REGION (__thread_info__->in_critical_region)
  748. #endif
  749. #ifndef DISABLE_CRITICAL_REGION
  750. #ifdef HAVE_KW_THREAD
  751. #define IN_CRITICAL_REGION sgen_thread_info->in_critical_region
  752. #else
  753. #define IN_CRITICAL_REGION (__thread_info__->in_critical_region)
  754. #endif
  755. /* Enter must be visible before anything is done in the critical region. */
  756. #define ENTER_CRITICAL_REGION do { mono_atomic_store_acquire (&IN_CRITICAL_REGION, 1); } while (0)
  757. /* Exit must make sure all critical regions stores are visible before it signal the end of the region.
  758. * We don't need to emit a full barrier since we
  759. */
  760. #define EXIT_CRITICAL_REGION do { mono_atomic_store_release (&IN_CRITICAL_REGION, 0); } while (0)
  761. #endif
  762. #ifdef HAVE_KW_THREAD
  763. #define EMIT_TLS_ACCESS(mb,dummy,offset) do { \
  764. mono_mb_emit_byte ((mb), MONO_CUSTOM_PREFIX); \
  765. mono_mb_emit_byte ((mb), CEE_MONO_TLS); \
  766. mono_mb_emit_i4 ((mb), (offset)); \
  767. } while (0)
  768. #else
  769. /*
  770. * CEE_MONO_TLS requires the tls offset, not the key, so the code below only works on darwin,
  771. * where the two are the same.
  772. */
  773. #if defined(__APPLE__) || defined (HOST_WIN32)
  774. #define EMIT_TLS_ACCESS(mb,member,dummy) do { \
  775. mono_mb_emit_byte ((mb), MONO_CUSTOM_PREFIX); \
  776. mono_mb_emit_byte ((mb), CEE_MONO_TLS); \
  777. mono_mb_emit_i4 ((mb), thread_info_key); \
  778. mono_mb_emit_icon ((mb), G_STRUCT_OFFSET (SgenThreadInfo, member)); \
  779. mono_mb_emit_byte ((mb), CEE_ADD); \
  780. mono_mb_emit_byte ((mb), CEE_LDIND_I); \
  781. } while (0)
  782. #else
  783. #define EMIT_TLS_ACCESS(mb,member,dummy) do { g_error ("sgen is not supported when using --with-tls=pthread.\n"); } while (0)
  784. #endif
  785. #endif
  786. /* Other globals */
  787. extern GCMemSection *nursery_section;
  788. extern int stat_major_gcs;
  789. extern guint32 collect_before_allocs;
  790. extern guint32 verify_before_allocs;
  791. extern gboolean has_per_allocation_action;
  792. extern int degraded_mode;
  793. extern int default_nursery_size;
  794. extern guint32 tlab_size;
  795. extern NurseryClearPolicy nursery_clear_policy;
  796. extern LOCK_DECLARE (gc_mutex);
  797. extern int do_pin_stats;
  798. /* Nursery helpers. */
  799. static inline void
  800. sgen_set_nursery_scan_start (char *p)
  801. {
  802. int idx = (p - (char*)nursery_section->data) / SGEN_SCAN_START_SIZE;
  803. char *old = nursery_section->scan_starts [idx];
  804. if (!old || old > p)
  805. nursery_section->scan_starts [idx] = p;
  806. }
  807. /* Object Allocation */
  808. typedef enum {
  809. ATYPE_NORMAL,
  810. ATYPE_VECTOR,
  811. ATYPE_SMALL,
  812. ATYPE_NUM
  813. } SgenAllocatorType;
  814. void sgen_init_tlab_info (SgenThreadInfo* info);
  815. void sgen_clear_tlabs (void);
  816. void sgen_set_use_managed_allocator (gboolean flag);
  817. gboolean sgen_is_managed_allocator (MonoMethod *method);
  818. gboolean sgen_has_managed_allocator (void);
  819. /* Debug support */
  820. void sgen_check_consistency (void);
  821. void sgen_check_major_refs (void);
  822. void sgen_check_whole_heap (gboolean allow_missing_pinning);
  823. void sgen_check_whole_heap_stw (void) MONO_INTERNAL;
  824. void sgen_check_objref (char *obj);
  825. void sgen_check_major_heap_marked (void) MONO_INTERNAL;
  826. void sgen_check_nursery_objects_pinned (gboolean pinned) MONO_INTERNAL;
  827. /* Write barrier support */
  828. /*
  829. * This causes the compile to extend the liveness of 'v' till the call to dummy_use
  830. */
  831. static inline void
  832. sgen_dummy_use (gpointer v) {
  833. #if defined(__GNUC__)
  834. __asm__ volatile ("" : "=r"(v) : "r"(v));
  835. #elif defined(_MSC_VER)
  836. __asm {
  837. mov eax, v;
  838. and eax, eax;
  839. };
  840. #else
  841. #error "Implement sgen_dummy_use for your compiler"
  842. #endif
  843. }
  844. /* Environment variable parsing */
  845. #define MONO_GC_PARAMS_NAME "MONO_GC_PARAMS"
  846. #define MONO_GC_DEBUG_NAME "MONO_GC_DEBUG"
  847. gboolean sgen_parse_environment_string_extract_number (const char *str, glong *out) MONO_INTERNAL;
  848. void sgen_env_var_error (const char *env_var, const char *fallback, const char *description_format, ...) MONO_INTERNAL;
  849. #endif /* HAVE_SGEN_GC */
  850. #endif /* __MONO_SGENGC_H__ */