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