2 * sgen-gc.c: Simple generational GC.
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
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;
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.
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.
22 #ifndef __MONO_SGENGC_H__
23 #define __MONO_SGENGC_H__
30 typedef struct _SgenThreadInfo SgenThreadInfo;
31 #define THREAD_INFO_TYPE SgenThreadInfo
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>
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
59 CLEAR_AT_TLAB_CREATION
62 NurseryClearPolicy sgen_get_nursery_clear_policy (void) MONO_INTERNAL;
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)
69 /* eventually share with MonoThread? */
71 * This structure extends the MonoThreadInfo structure.
73 struct _SgenThreadInfo {
76 This is set to TRUE when STW fails to suspend a thread, most probably because the
77 underlying thread is dead.
80 volatile int in_critical_region;
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
87 Our hope is that those threads are harmlesly blocked in the GC lock trying to finish registration.
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.
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.
99 gboolean doing_handshake;
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
106 gboolean thread_is_dying;
109 This is set the argument of mono_gc_set_skip_thread.
111 A thread that knowingly holds no managed state can call this
112 function around blocking loops to reduce the GC burden by not
115 gboolean gc_disabled;
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;
125 /* Only used on POSIX platforms */
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. */
131 gpointer stopped_ip; /* only valid if the thread is stopped */
132 MonoDomain *stopped_domain; /* dsto */
134 /*FIXME pretty please finish killing ARCH_NUM_REGS */
136 MonoContext ctx; /* ditto */
138 gpointer regs[ARCH_NUM_REGS]; /* ditto */
141 #ifndef HAVE_KW_THREAD
150 * The nursery section uses this struct.
152 typedef struct _GCMemSection GCMemSection;
153 struct _GCMemSection {
156 /* pointer where more data could be allocated if it fits */
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.
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;
171 * Recursion is not allowed for the thread lock.
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); \
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 (); \
187 extern LOCK_DECLARE (sgen_interruption_mutex);
189 #define LOCK_INTERRUPTION mono_mutex_lock (&sgen_interruption_mutex)
190 #define UNLOCK_INTERRUPTION mono_mutex_unlock (&sgen_interruption_mutex)
192 /* FIXME: Use InterlockedAdd & InterlockedAdd64 to reduce the CAS cost. */
193 #define SGEN_CAS_PTR InterlockedCompareExchangePointer
194 #define SGEN_ATOMIC_ADD(x,i) do { \
198 } while (InterlockedCompareExchange (&(x), __old_x + (i), __old_x) != __old_x); \
200 #define SGEN_ATOMIC_ADD_P(x,i) do { \
204 } while (InterlockedCompareExchangePointer ((void**)&(x), (void*)(__old_x + (i)), (void*)__old_x) != (void*)__old_x); \
209 /* we intercept pthread_create calls to know which threads exist */
210 #define USE_PTHREAD_INTERCEPT 1
213 #ifdef HEAVY_STATISTICS
214 #define HEAVY_STAT(x) x
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;
221 #define HEAVY_STAT(x)
224 #define SGEN_ASSERT(level, a, ...) do { \
225 if (G_UNLIKELY ((level) <= SGEN_MAX_ASSERT_LEVEL && !(a))) { \
226 g_error (__VA_ARGS__); \
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__); \
235 #define SGEN_COND_LOG(level, cond, format, ...) do { \
236 if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) { \
238 mono_gc_printf (gc_debug_file, format, ##__VA_ARGS__); \
241 #define SGEN_LOG_DO(level, fun) do { \
242 if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) { \
246 extern int gc_debug_level;
247 extern FILE* gc_debug_file;
249 extern int current_collection_generation;
251 extern unsigned int sgen_global_stop_count;
253 extern gboolean bridge_processing_in_progress;
255 extern int num_ready_finalizers;
257 #define SGEN_ALLOC_ALIGN 8
258 #define SGEN_ALLOC_ALIGN_BITS 3
260 #define SGEN_ALIGN_UP(s) (((s)+(SGEN_ALLOC_ALIGN-1)) & ~(SGEN_ALLOC_ALIGN-1))
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.
267 #define HIDE_POINTER(p,t) ((gpointer)(~((gulong)(p)|((t)?1:0))))
268 #define REVEAL_POINTER(p) ((gpointer)((~(gulong)(p))&~3L))
270 #ifdef SGEN_ALIGN_NURSERY
271 #define SGEN_PTR_IN_NURSERY(p,bits,start,end) (((mword)(p) & ~((1 << (bits)) - 1)) == (mword)(start))
273 #define SGEN_PTR_IN_NURSERY(p,bits,start,end) ((char*)(p) >= (start) && (char*)(p) < (end))
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;
289 #define DEFAULT_NURSERY_SIZE (4*1024*1024)
290 #ifdef SGEN_ALIGN_NURSERY
291 #define DEFAULT_NURSERY_BITS 22
296 #ifndef SGEN_ALIGN_NURSERY
297 #define DEFAULT_NURSERY_BITS -1
300 extern char *sgen_nursery_start MONO_INTERNAL;
301 extern char *sgen_nursery_end MONO_INTERNAL;
303 static inline gboolean
304 sgen_ptr_in_nursery (void *p)
306 return SGEN_PTR_IN_NURSERY ((p), DEFAULT_NURSERY_BITS, sgen_nursery_start, sgen_nursery_end);
310 sgen_get_nursery_start (void)
312 return sgen_nursery_start;
316 sgen_get_nursery_end (void)
318 return sgen_nursery_end;
321 /* Structure that corresponds to a MonoVTable: desc is a mword so requires
322 * no cast from a pointer to an integer
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.
338 #define SGEN_FORWARDED_BIT 1
339 #define SGEN_PINNED_BIT 2
340 #define SGEN_VTABLE_BITS_MASK 0x3
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)
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; \
350 #define SGEN_PIN_OBJECT(obj) do { \
351 ((mword*)(obj))[0] |= SGEN_PINNED_BIT; \
353 #define SGEN_UNPIN_OBJECT(obj) do { \
354 ((mword*)(obj))[0] &= ~SGEN_PINNED_BIT; \
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.
361 #define SGEN_LOAD_VTABLE(addr) ((*(mword*)(addr)) & ~SGEN_VTABLE_BITS_MASK)
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)))
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)); \
371 (queue)->first->objects [(queue)->first->end++] = (o); \
374 #define GRAY_OBJECT_DEQUEUE(queue,o) do { \
375 if (!(queue)->first) \
377 else if (G_UNLIKELY ((queue)->first->end == 1)) \
378 (o) = sgen_gray_object_dequeue ((queue)); \
380 (o) = (queue)->first->objects [--(queue)->first->end]; \
385 List of what each bit on of the vtable gc bits means.
388 SGEN_GC_BIT_BRIDGE_OBJECT = 1,
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).
395 typedef struct _RootRecord RootRecord;
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 */
408 extern SgenHashTable roots_hash [ROOT_TYPE_NUM];
410 typedef void (*IterateObjectCallbackFunc) (char*, size_t, void*);
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;
419 gboolean sgen_is_worker_thread (MonoNativeThreadId thread) MONO_INTERNAL;
421 void sgen_update_heap_boundaries (mword low, mword high) MONO_INTERNAL;
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;
426 /* Keep in sync with description_for_type() in sgen-internal.c! */
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,
466 #ifdef SGEN_BINARY_PROTOCOL
467 #define BINARY_PROTOCOL_ARG(x) ,x
469 #define BINARY_PROTOCOL_ARG(x)
472 void sgen_init_internal_allocator (void) MONO_INTERNAL;
474 typedef struct _ObjectList ObjectList;
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));
486 ScanObjectFunc scan_func;
487 CopyOrMarkObjectFunc copy_func;
488 SgenGrayQueue *queue;
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;
496 void sgen_register_moved_object (void *obj, void *destination) MONO_INTERNAL;
498 void sgen_register_fixed_internal_mem_type (int type, size_t size) MONO_INTERNAL;
500 void* sgen_alloc_internal (int type) MONO_INTERNAL;
501 void sgen_free_internal (void *addr, int type) MONO_INTERNAL;
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;
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;
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);
514 void sgen_sort_addresses (void **array, int size) MONO_INTERNAL;
515 void sgen_add_to_global_remset (gpointer ptr, gpointer obj) MONO_INTERNAL;
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;
523 CopyOrMarkObjectFunc copy_or_mark_object;
524 ScanObjectFunc scan_object;
525 ScanVTypeFunc scan_vtype;
526 /*FIXME add allocation function? */
527 } SgenObjectOperations;
529 SgenObjectOperations *sgen_get_current_object_ops (void) MONO_INTERNAL;
531 typedef struct _SgenFragment SgenFragment;
533 struct _SgenFragment {
535 char *fragment_start;
536 char *fragment_next; /* the current soft limit for allocation */
538 SgenFragment *next_in_order; /* We use a different entry for all active fragments so we can avoid SMR. */
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;
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;
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%.
562 Experimental results on how much space we waste with a 4Mb nursery:
564 Note that the wastage applies to the half nursery, or 2Mb:
566 Test 1 (compiling corlib):
571 #define SGEN_TO_SPACE_GRANULE_BITS 9
572 #define SGEN_TO_SPACE_GRANULE_IN_BYTES (1 << SGEN_TO_SPACE_GRANULE_BITS)
574 extern char *sgen_space_bitmap MONO_INTERNAL;
575 extern int sgen_space_bitmap_size MONO_INTERNAL;
577 static inline gboolean
578 sgen_nursery_is_to_space (char *object)
580 int idx = (object - sgen_nursery_start) >> SGEN_TO_SPACE_GRANULE_BITS;
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);
587 return (sgen_space_bitmap [byte] & (1 << bit)) != 0;
590 static inline gboolean
591 sgen_nursery_is_from_space (char *object)
593 return !sgen_nursery_is_to_space (object);
596 static inline gboolean
597 sgen_nursery_is_object_alive (char *obj)
599 /* FIXME put this asserts under a non default level */
600 g_assert (sgen_ptr_in_nursery (obj));
602 if (sgen_nursery_is_to_space (obj))
605 if (SGEN_OBJECT_IS_PINNED (obj) || SGEN_OBJECT_IS_FORWARDED (obj))
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);
617 SgenObjectOperations serial_ops;
618 SgenObjectOperations parallel_ops;
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);
627 gboolean (*handle_gc_param) (const char *opt); /* Optional */
628 void (*print_gc_param_usage) (void); /* Optional */
629 } SgenMinorCollector;
631 extern SgenMinorCollector sgen_minor_collector;
633 void sgen_simple_nursery_init (SgenMinorCollector *collector) MONO_INTERNAL;
634 void sgen_split_nursery_init (SgenMinorCollector *collector) MONO_INTERNAL;
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;
639 typedef struct _SgenMajorCollector SgenMajorCollector;
640 struct _SgenMajorCollector {
642 gboolean is_parallel;
643 gboolean is_concurrent;
644 gboolean supports_cardtable;
645 gboolean sweeps_lazily;
648 * This is set to TRUE if the sweep for the last major
649 * collection has been completed.
651 gboolean *have_swept;
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.
657 gboolean *want_synchronous_collection;
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);
664 SgenObjectOperations major_ops;
665 SgenObjectOperations major_concurrent_ops;
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);
705 extern SgenMajorCollector major_collector;
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;
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);
724 void (*finish_scan_remsets) (void *start_nursery, void *end_nursery, SgenGrayQueue *queue);
726 void (*prepare_for_major_collection) (void);
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);
733 SgenRemeberedSet *sgen_get_remset (void) MONO_INTERNAL;
735 static guint /*__attribute__((noinline)) not sure if this hint is a good idea*/
736 slow_object_get_size (MonoVTable *vtable, MonoObject* o)
738 MonoClass *klass = vtable->klass;
741 * We depend on mono_string_length_fast and
742 * mono_array_length_fast not using the object's vtable.
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;
756 /* from a created object: the class must be inited already */
757 return klass->instance_size;
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
767 sgen_par_object_get_size (MonoVTable *vtable, MonoObject* o)
769 mword descr = (mword)vtable->gc_descr;
770 mword type = descr & 0x7;
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;
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);
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;
790 return slow_object_get_size (vtable, o);
794 sgen_safe_object_get_size (MonoObject *obj)
798 if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj)))
799 obj = (MonoObject*)forwarded;
801 return sgen_par_object_get_size ((MonoVTable*)SGEN_LOAD_VTABLE (obj), obj);
804 const char* sgen_safe_name (void* obj) MONO_INTERNAL;
806 gboolean sgen_object_is_live (void *obj) MONO_INTERNAL;
808 void sgen_init_fin_weak_hash (void) MONO_INTERNAL;
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;
820 void sgen_scan_togglerefs (char *start, char *end, ScanCopyContext ctx) MONO_INTERNAL;
821 void sgen_process_togglerefs (void) MONO_INTERNAL;
823 typedef mono_bool (*WeakLinkAlivePredicateFunc) (MonoObject*, void*);
825 void sgen_null_links_with_predicate (int generation, WeakLinkAlivePredicateFunc predicate, void *data) MONO_INTERNAL;
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;
832 void sgen_queue_finalization_entry (MonoObject *obj) MONO_INTERNAL;
833 const char* sgen_generation_name (int generation) MONO_INTERNAL;
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;
844 gboolean sgen_drain_gray_stack (int max_objs, ScanCopyContext ctx) MONO_INTERNAL;
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;
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;
866 gboolean is_overflow;
867 SGEN_TV_DECLARE (total_time);
868 SGEN_TV_DECLARE (stw_time);
869 SGEN_TV_DECLARE (bridge_time);
872 int sgen_stop_world (int generation) MONO_INTERNAL;
873 int sgen_restart_world (int generation, GGTimingInfo *timing) MONO_INTERNAL;
877 typedef struct _LOSObject LOSObject;
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) */
885 char data [MONO_ZERO_LEN_ARRAY];
888 #define ARRAY_OBJ_INDEX(ptr,array,elem_size) (((char*)(ptr) - ((char*)(array) + G_STRUCT_OFFSET (MonoArray, vector))) / (elem_size))
890 extern LOSObject *los_object_list;
891 extern mword los_memory_usage;
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;
911 /* nursery allocator */
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;
927 void sgen_nursery_alloc_prepare_for_minor (void) MONO_INTERNAL;
928 void sgen_nursery_alloc_prepare_for_major (void) MONO_INTERNAL;
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;
935 extern MonoNativeTlsKey thread_info_key;
937 #ifdef HAVE_KW_THREAD
938 extern __thread SgenThreadInfo *sgen_thread_info;
939 extern __thread char *stack_end;
942 #ifdef HAVE_KW_THREAD
943 #define TLAB_ACCESS_INIT
944 #define IN_CRITICAL_REGION sgen_thread_info->in_critical_region
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)
950 #ifndef DISABLE_CRITICAL_REGION
952 #ifdef HAVE_KW_THREAD
953 #define IN_CRITICAL_REGION sgen_thread_info->in_critical_region
955 #define IN_CRITICAL_REGION (__thread_info__->in_critical_region)
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)
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
964 #define EXIT_CRITICAL_REGION do { mono_atomic_store_release (&IN_CRITICAL_REGION, 0); } while (0)
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)); \
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.
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); \
990 #define EMIT_TLS_ACCESS(mb,member,dummy) do { g_error ("sgen is not supported when using --with-tls=pthread.\n"); } while (0)
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;
1007 extern LOCK_DECLARE (gc_mutex);
1009 extern int do_pin_stats;
1011 /* Nursery helpers. */
1014 sgen_set_nursery_scan_start (char *p)
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;
1023 /* Object Allocation */
1031 } SgenAllocatorType;
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);
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;
1050 /* Write barrier support */
1053 * This causes the compile to extend the liveness of 'v' till the call to dummy_use
1056 sgen_dummy_use (gpointer v) {
1057 #if defined(__GNUC__)
1058 __asm__ volatile ("" : "=r"(v) : "r"(v));
1059 #elif defined(_MSC_VER)
1065 #error "Implement sgen_dummy_use for your compiler"
1069 /* Environment variable parsing */
1071 #define MONO_GC_PARAMS_NAME "MONO_GC_PARAMS"
1072 #define MONO_GC_DEBUG_NAME "MONO_GC_DEBUG"
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;
1077 #endif /* HAVE_SGEN_GC */
1079 #endif /* __MONO_SGENGC_H__ */