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>
51 #include <mono/metadata/sgen-bridge.h>
52 #include <mono/metadata/sgen-protocol.h>
54 /* The method used to clear the nursery */
55 /* Clearing at nursery collections is the safest, but has bad interactions with caches.
56 * Clearing at TLAB creation is much faster, but more complex and it might expose hard
61 CLEAR_AT_TLAB_CREATION
,
62 CLEAR_AT_TLAB_CREATION_DEBUG
65 NurseryClearPolicy
sgen_get_nursery_clear_policy (void) MONO_INTERNAL
;
67 #define SGEN_TV_DECLARE(name) gint64 name
68 #define SGEN_TV_GETTIME(tv) tv = mono_100ns_ticks ()
69 #define SGEN_TV_ELAPSED(start,end) (int)((end-start))
70 #define SGEN_TV_ELAPSED_MS(start,end) ((SGEN_TV_ELAPSED((start),(end)) + 5000) / 10000)
72 #if !defined(__MACH__) && !MONO_MACH_ARCH_SUPPORTED && defined(HAVE_PTHREAD_KILL)
73 #define SGEN_POSIX_STW 1
76 /* eventually share with MonoThread? */
78 * This structure extends the MonoThreadInfo structure.
80 struct _SgenThreadInfo
{
83 This is set to TRUE when STW fails to suspend a thread, most probably because the
84 underlying thread is dead.
87 volatile int in_critical_region
;
90 This is set the argument of mono_gc_set_skip_thread.
92 A thread that knowingly holds no managed state can call this
93 function around blocking loops to reduce the GC burden by not
99 void *stack_start_limit
;
100 char **tlab_next_addr
;
101 char **tlab_start_addr
;
102 char **tlab_temp_end_addr
;
103 char **tlab_real_end_addr
;
104 gpointer runtime_data
;
106 #ifdef SGEN_POSIX_STW
107 /* This is -1 until the first suspend. */
109 /* FIXME: kill this, we only use signals on systems that have rt-posix, which doesn't have issues with duplicates. */
110 unsigned int stop_count
; /* to catch duplicate signals. */
113 gpointer stopped_ip
; /* only valid if the thread is stopped */
114 MonoDomain
*stopped_domain
; /* dsto */
116 /*FIXME pretty please finish killing ARCH_NUM_REGS */
118 MonoContext ctx
; /* ditto */
120 gpointer regs
[ARCH_NUM_REGS
]; /* ditto */
123 #ifndef HAVE_KW_THREAD
132 * The nursery section uses this struct.
134 typedef struct _GCMemSection GCMemSection
;
135 struct _GCMemSection
{
138 /* pointer where more data could be allocated if it fits */
142 * scan starts is an array of pointers to objects equally spaced in the allocation area
143 * They let use quickly find pinned objects from pinning pointers.
146 /* in major collections indexes in the pin_queue for objects that pin this section */
147 void **pin_queue_start
;
148 size_t pin_queue_num_entries
;
149 size_t num_scan_start
;
153 * Recursion is not allowed for the thread lock.
155 #define LOCK_DECLARE(name) mono_mutex_t name
156 /* if changing LOCK_INIT to something that isn't idempotent, look at
157 its use in mono_gc_base_init in sgen-gc.c */
158 #define LOCK_INIT(name) mono_mutex_init (&(name))
159 #define LOCK_GC do { \
160 mono_mutex_lock (&gc_mutex); \
163 #define TRYLOCK_GC (mono_mutex_trylock (&gc_mutex) == 0)
164 #define UNLOCK_GC do { sgen_gc_unlock (); } while (0)
166 extern LOCK_DECLARE (sgen_interruption_mutex
);
168 #define LOCK_INTERRUPTION mono_mutex_lock (&sgen_interruption_mutex)
169 #define UNLOCK_INTERRUPTION mono_mutex_unlock (&sgen_interruption_mutex)
171 /* FIXME: Use InterlockedAdd & InterlockedAdd64 to reduce the CAS cost. */
172 #define SGEN_CAS_PTR InterlockedCompareExchangePointer
173 #define SGEN_ATOMIC_ADD(x,i) do { \
177 } while (InterlockedCompareExchange (&(x), __old_x + (i), __old_x) != __old_x); \
179 #define SGEN_ATOMIC_ADD_P(x,i) do { \
183 } while (InterlockedCompareExchangePointer ((void**)&(x), (void*)(__old_x + (i)), (void*)__old_x) != (void*)__old_x); \
188 /* we intercept pthread_create calls to know which threads exist */
189 #define USE_PTHREAD_INTERCEPT 1
192 #ifdef HEAVY_STATISTICS
193 extern long long stat_objects_alloced_degraded
;
194 extern long long stat_bytes_alloced_degraded
;
195 extern long long stat_copy_object_called_major
;
196 extern long long stat_objects_copied_major
;
199 #define SGEN_ASSERT(level, a, ...) do { \
200 if (G_UNLIKELY ((level) <= SGEN_MAX_ASSERT_LEVEL && !(a))) { \
201 g_error (__VA_ARGS__); \
205 #define SGEN_LOG(level, format, ...) do { \
206 if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) { \
207 mono_gc_printf (gc_debug_file, format, ##__VA_ARGS__); \
210 #define SGEN_COND_LOG(level, cond, format, ...) do { \
211 if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) { \
213 mono_gc_printf (gc_debug_file, format, ##__VA_ARGS__); \
216 #define SGEN_LOG_DO(level, fun) do { \
217 if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) { \
221 extern int gc_debug_level
;
222 extern FILE* gc_debug_file
;
224 extern int current_collection_generation
;
226 extern unsigned int sgen_global_stop_count
;
228 extern gboolean bridge_processing_in_progress
;
229 extern MonoGCBridgeCallbacks bridge_callbacks
;
231 extern int num_ready_finalizers
;
233 #define SGEN_ALLOC_ALIGN 8
234 #define SGEN_ALLOC_ALIGN_BITS 3
236 /* s must be non-negative */
237 #define SGEN_CAN_ALIGN_UP(s) ((s) <= SIZE_MAX - (SGEN_ALLOC_ALIGN - 1))
238 #define SGEN_ALIGN_UP(s) (((s)+(SGEN_ALLOC_ALIGN-1)) & ~(SGEN_ALLOC_ALIGN-1))
240 #if SIZEOF_VOID_P == 4
247 * The link pointer is hidden by negating each bit. We use the lowest
248 * bit of the link (before negation) to store whether it needs
249 * resurrection tracking.
251 #define HIDE_POINTER(p,t) ((gpointer)(~((size_t)(p)|((t)?1:0))))
252 #define REVEAL_POINTER(p) ((gpointer)((~(size_t)(p))&~3L))
254 #ifdef SGEN_ALIGN_NURSERY
255 #define SGEN_PTR_IN_NURSERY(p,bits,start,end) (((mword)(p) & ~((1 << (bits)) - 1)) == (mword)(start))
257 #define SGEN_PTR_IN_NURSERY(p,bits,start,end) ((char*)(p) >= (start) && (char*)(p) < (end))
262 /* good sizes are 512KB-1MB: larger ones increase a lot memzeroing time */
263 #define DEFAULT_NURSERY_SIZE (sgen_nursery_size)
264 extern size_t sgen_nursery_size MONO_INTERNAL
;
265 #ifdef SGEN_ALIGN_NURSERY
266 /* The number of trailing 0 bits in DEFAULT_NURSERY_SIZE */
267 #define DEFAULT_NURSERY_BITS (sgen_nursery_bits)
268 extern int sgen_nursery_bits MONO_INTERNAL
;
273 #define DEFAULT_NURSERY_SIZE (4*1024*1024)
274 #ifdef SGEN_ALIGN_NURSERY
275 #define DEFAULT_NURSERY_BITS 22
280 #ifndef SGEN_ALIGN_NURSERY
281 #define DEFAULT_NURSERY_BITS -1
284 extern char *sgen_nursery_start MONO_INTERNAL
;
285 extern char *sgen_nursery_end MONO_INTERNAL
;
287 static inline MONO_ALWAYS_INLINE gboolean
288 sgen_ptr_in_nursery (void *p
)
290 return SGEN_PTR_IN_NURSERY ((p
), DEFAULT_NURSERY_BITS
, sgen_nursery_start
, sgen_nursery_end
);
293 static inline MONO_ALWAYS_INLINE
char*
294 sgen_get_nursery_start (void)
296 return sgen_nursery_start
;
299 static inline MONO_ALWAYS_INLINE
char*
300 sgen_get_nursery_end (void)
302 return sgen_nursery_end
;
305 /* Structure that corresponds to a MonoVTable: desc is a mword so requires
306 * no cast from a pointer to an integer
313 /* these bits are set in the object vtable: we could merge them since an object can be
314 * either pinned or forwarded but not both.
315 * We store them in the vtable slot because the bits are used in the sync block for
316 * other purposes: if we merge them and alloc the sync blocks aligned to 8 bytes, we can change
317 * this and use bit 3 in the syncblock (with the lower two bits both set for forwarded, that
318 * would be an invalid combination for the monitor and hash code).
319 * The values are already shifted.
320 * The forwarding address is stored in the sync block.
323 #define SGEN_VTABLE_BITS_MASK 0x3
325 #include "sgen-tagged-pointer.h"
327 #define SGEN_POINTER_IS_TAGGED_FORWARDED(p) SGEN_POINTER_IS_TAGGED_1((p))
328 #define SGEN_POINTER_TAG_FORWARDED(p) SGEN_POINTER_TAG_1((p))
330 #define SGEN_POINTER_IS_TAGGED_PINNED(p) SGEN_POINTER_IS_TAGGED_2((p))
331 #define SGEN_POINTER_TAG_PINNED(p) SGEN_POINTER_TAG_2((p))
333 #define SGEN_POINTER_UNTAG_VTABLE(p) SGEN_POINTER_UNTAG_12((p))
335 /* returns NULL if not forwarded, or the forwarded address */
336 #define SGEN_VTABLE_IS_FORWARDED(vtable) (SGEN_POINTER_IS_TAGGED_FORWARDED ((vtable)) ? SGEN_POINTER_UNTAG_VTABLE ((vtable)) : NULL)
337 #define SGEN_OBJECT_IS_FORWARDED(obj) (SGEN_VTABLE_IS_FORWARDED (((mword*)(obj))[0]))
339 #define SGEN_VTABLE_IS_PINNED(vtable) SGEN_POINTER_IS_TAGGED_PINNED ((vtable))
340 #define SGEN_OBJECT_IS_PINNED(obj) (SGEN_VTABLE_IS_PINNED (((mword*)(obj))[0]))
342 /* set the forwarded address fw_addr for object obj */
343 #define SGEN_FORWARD_OBJECT(obj,fw_addr) do { \
344 *(void**)(obj) = SGEN_POINTER_TAG_FORWARDED ((fw_addr)); \
346 #define SGEN_PIN_OBJECT(obj) do { \
347 *(void**)(obj) = SGEN_POINTER_TAG_PINNED (*(void**)(obj)); \
349 #define SGEN_UNPIN_OBJECT(obj) do { \
350 *(void**)(obj) = SGEN_POINTER_UNTAG_2 (*(void**)(obj)); \
354 * Since we set bits in the vtable, use the macro to load it from the pointer to
355 * an object that is potentially pinned.
357 #define SGEN_LOAD_VTABLE(addr) SGEN_POINTER_UNTAG_12 (*(void**)(addr))
360 List of what each bit on of the vtable gc bits means.
363 SGEN_GC_BIT_BRIDGE_OBJECT
= 1,
364 SGEN_GC_BIT_BRIDGE_OPAQUE_OBJECT
= 2,
365 SGEN_GC_BIT_FINALIZER_AWARE
= 4,
368 /* the runtime can register areas of memory as roots: we keep two lists of roots,
369 * a pinned root set for conservatively scanned roots and a normal one for
370 * precisely scanned roots (currently implemented as a single list).
372 typedef struct _RootRecord RootRecord
;
379 ROOT_TYPE_NORMAL
= 0, /* "normal" roots */
380 ROOT_TYPE_PINNED
= 1, /* roots without a GC descriptor */
381 ROOT_TYPE_WBARRIER
= 2, /* roots with a write barrier */
385 extern SgenHashTable roots_hash
[ROOT_TYPE_NUM
];
387 typedef void (*IterateObjectCallbackFunc
) (char*, size_t, void*);
389 int sgen_thread_handshake (BOOL suspend
) MONO_INTERNAL
;
390 gboolean
sgen_suspend_thread (SgenThreadInfo
*info
) MONO_INTERNAL
;
391 gboolean
sgen_resume_thread (SgenThreadInfo
*info
) MONO_INTERNAL
;
392 void sgen_wait_for_suspend_ack (int count
) MONO_INTERNAL
;
393 void sgen_os_init (void) MONO_INTERNAL
;
395 gboolean
sgen_is_worker_thread (MonoNativeThreadId thread
) MONO_INTERNAL
;
397 void sgen_update_heap_boundaries (mword low
, mword high
) MONO_INTERNAL
;
399 void sgen_scan_area_with_callback (char *start
, char *end
, IterateObjectCallbackFunc callback
, void *data
, gboolean allow_flags
) MONO_INTERNAL
;
400 void sgen_check_section_scan_starts (GCMemSection
*section
) MONO_INTERNAL
;
402 /* Keep in sync with description_for_type() in sgen-internal.c! */
404 INTERNAL_MEM_PIN_QUEUE
,
405 INTERNAL_MEM_FRAGMENT
,
406 INTERNAL_MEM_SECTION
,
407 INTERNAL_MEM_SCAN_STARTS
,
408 INTERNAL_MEM_FIN_TABLE
,
409 INTERNAL_MEM_FINALIZE_ENTRY
,
410 INTERNAL_MEM_FINALIZE_READY_ENTRY
,
411 INTERNAL_MEM_DISLINK_TABLE
,
412 INTERNAL_MEM_DISLINK
,
413 INTERNAL_MEM_ROOTS_TABLE
,
414 INTERNAL_MEM_ROOT_RECORD
,
415 INTERNAL_MEM_STATISTICS
,
416 INTERNAL_MEM_STAT_PINNED_CLASS
,
417 INTERNAL_MEM_STAT_REMSET_CLASS
,
418 INTERNAL_MEM_GRAY_QUEUE
,
419 INTERNAL_MEM_MS_TABLES
,
420 INTERNAL_MEM_MS_BLOCK_INFO
,
421 INTERNAL_MEM_MS_BLOCK_INFO_SORT
,
422 INTERNAL_MEM_EPHEMERON_LINK
,
423 INTERNAL_MEM_WORKER_DATA
,
424 INTERNAL_MEM_WORKER_JOB_DATA
,
425 INTERNAL_MEM_BRIDGE_DATA
,
426 INTERNAL_MEM_OLD_BRIDGE_HASH_TABLE
,
427 INTERNAL_MEM_OLD_BRIDGE_HASH_TABLE_ENTRY
,
428 INTERNAL_MEM_BRIDGE_HASH_TABLE
,
429 INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY
,
430 INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE
,
431 INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE_ENTRY
,
432 INTERNAL_MEM_TARJAN_BRIDGE_HASH_TABLE
,
433 INTERNAL_MEM_TARJAN_BRIDGE_HASH_TABLE_ENTRY
,
434 INTERNAL_MEM_TARJAN_OBJ_BUCKET
,
435 INTERNAL_MEM_BRIDGE_DEBUG
,
436 INTERNAL_MEM_JOB_QUEUE_ENTRY
,
437 INTERNAL_MEM_TOGGLEREF_DATA
,
438 INTERNAL_MEM_CARDTABLE_MOD_UNION
,
439 INTERNAL_MEM_BINARY_PROTOCOL
,
449 #ifdef SGEN_HEAVY_BINARY_PROTOCOL
450 #define BINARY_PROTOCOL_ARG(x) ,x
452 #define BINARY_PROTOCOL_ARG(x)
455 void sgen_init_internal_allocator (void) MONO_INTERNAL
;
457 typedef struct _ObjectList ObjectList
;
463 typedef void (*CopyOrMarkObjectFunc
) (void**, SgenGrayQueue
*);
464 typedef void (*ScanObjectFunc
) (char *obj
, mword desc
, SgenGrayQueue
*);
465 typedef void (*ScanVTypeFunc
) (char*, mword desc
, SgenGrayQueue
* BINARY_PROTOCOL_ARG (size_t size
));
469 ScanObjectFunc scan_func
;
470 CopyOrMarkObjectFunc copy_func
;
471 SgenGrayQueue
*queue
;
474 void sgen_report_internal_mem_usage (void) MONO_INTERNAL
;
475 void sgen_dump_internal_mem_usage (FILE *heap_dump_file
) MONO_INTERNAL
;
476 void sgen_dump_section (GCMemSection
*section
, const char *type
) MONO_INTERNAL
;
477 void sgen_dump_occupied (char *start
, char *end
, char *section_start
) MONO_INTERNAL
;
479 void sgen_register_moved_object (void *obj
, void *destination
) MONO_INTERNAL
;
481 void sgen_register_fixed_internal_mem_type (int type
, size_t size
) MONO_INTERNAL
;
483 void* sgen_alloc_internal (int type
) MONO_INTERNAL
;
484 void sgen_free_internal (void *addr
, int type
) MONO_INTERNAL
;
486 void* sgen_alloc_internal_dynamic (size_t size
, int type
, gboolean assert_on_failure
) MONO_INTERNAL
;
487 void sgen_free_internal_dynamic (void *addr
, size_t size
, int type
) MONO_INTERNAL
;
489 void** sgen_find_optimized_pin_queue_area (void *start
, void *end
, size_t *num
) MONO_INTERNAL
;
490 void sgen_find_section_pin_queue_start_end (GCMemSection
*section
) MONO_INTERNAL
;
491 void sgen_pin_objects_in_section (GCMemSection
*section
, ScanCopyContext ctx
) MONO_INTERNAL
;
493 void sgen_pin_stats_register_object (char *obj
, size_t size
);
494 void sgen_pin_stats_register_global_remset (char *obj
);
495 void sgen_pin_stats_print_class_stats (void);
497 void sgen_sort_addresses (void **array
, size_t size
) MONO_INTERNAL
;
498 void sgen_add_to_global_remset (gpointer ptr
, gpointer obj
) MONO_INTERNAL
;
500 int sgen_get_current_collection_generation (void) MONO_INTERNAL
;
501 gboolean
sgen_collection_is_concurrent (void) MONO_INTERNAL
;
502 gboolean
sgen_concurrent_collection_in_progress (void) MONO_INTERNAL
;
505 CopyOrMarkObjectFunc copy_or_mark_object
;
506 ScanObjectFunc scan_object
;
507 ScanVTypeFunc scan_vtype
;
508 /*FIXME add allocation function? */
509 } SgenObjectOperations
;
511 SgenObjectOperations
*sgen_get_current_object_ops (void) MONO_INTERNAL
;
513 typedef struct _SgenFragment SgenFragment
;
515 struct _SgenFragment
{
517 char *fragment_start
;
518 char *fragment_next
; /* the current soft limit for allocation */
520 SgenFragment
*next_in_order
; /* We use a different entry for all active fragments so we can avoid SMR. */
524 SgenFragment
*alloc_head
; /* List head to be used when allocating memory. Walk with fragment_next. */
525 SgenFragment
*region_head
; /* List head of the region used by this allocator. Walk with next_in_order. */
526 } SgenFragmentAllocator
;
528 void sgen_fragment_allocator_add (SgenFragmentAllocator
*allocator
, char *start
, char *end
) MONO_INTERNAL
;
529 void sgen_fragment_allocator_release (SgenFragmentAllocator
*allocator
) MONO_INTERNAL
;
530 void* sgen_fragment_allocator_serial_alloc (SgenFragmentAllocator
*allocator
, size_t size
) MONO_INTERNAL
;
531 void* sgen_fragment_allocator_par_alloc (SgenFragmentAllocator
*allocator
, size_t size
) MONO_INTERNAL
;
532 void* sgen_fragment_allocator_serial_range_alloc (SgenFragmentAllocator
*allocator
, size_t desired_size
, size_t minimum_size
, size_t *out_alloc_size
) MONO_INTERNAL
;
533 void* sgen_fragment_allocator_par_range_alloc (SgenFragmentAllocator
*allocator
, size_t desired_size
, size_t minimum_size
, size_t *out_alloc_size
) MONO_INTERNAL
;
534 SgenFragment
* sgen_fragment_allocator_alloc (void) MONO_INTERNAL
;
535 void sgen_clear_allocator_fragments (SgenFragmentAllocator
*allocator
) MONO_INTERNAL
;
536 void sgen_clear_range (char *start
, char *end
) MONO_INTERNAL
;
540 This is a space/speed compromise as we need to make sure the from/to space check is both O(1)
541 and only hit cache hot memory. On a 4Mb nursery it requires 1024 bytes, or 3% of your average
542 L1 cache. On small configs with a 512kb nursery, this goes to 0.4%.
544 Experimental results on how much space we waste with a 4Mb nursery:
546 Note that the wastage applies to the half nursery, or 2Mb:
548 Test 1 (compiling corlib):
553 #define SGEN_TO_SPACE_GRANULE_BITS 9
554 #define SGEN_TO_SPACE_GRANULE_IN_BYTES (1 << SGEN_TO_SPACE_GRANULE_BITS)
556 extern char *sgen_space_bitmap MONO_INTERNAL
;
557 extern size_t sgen_space_bitmap_size MONO_INTERNAL
;
559 static inline gboolean
560 sgen_nursery_is_to_space (char *object
)
562 size_t idx
= (object
- sgen_nursery_start
) >> SGEN_TO_SPACE_GRANULE_BITS
;
563 size_t byte
= idx
>> 3;
564 size_t bit
= idx
& 0x7;
566 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 ());
567 SGEN_ASSERT (4, byte
< sgen_space_bitmap_size
, "byte index %d out of range", byte
, sgen_space_bitmap_size
);
569 return (sgen_space_bitmap
[byte
] & (1 << bit
)) != 0;
572 static inline gboolean
573 sgen_nursery_is_from_space (char *object
)
575 return !sgen_nursery_is_to_space (object
);
578 static inline gboolean
579 sgen_nursery_is_object_alive (char *obj
)
581 /* FIXME put this asserts under a non default level */
582 g_assert (sgen_ptr_in_nursery (obj
));
584 if (sgen_nursery_is_to_space (obj
))
587 if (SGEN_OBJECT_IS_PINNED (obj
) || SGEN_OBJECT_IS_FORWARDED (obj
))
596 char* (*alloc_for_promotion
) (MonoVTable
*vtable
, char *obj
, size_t objsize
, gboolean has_references
);
598 SgenObjectOperations serial_ops
;
600 void (*prepare_to_space
) (char *to_space_bitmap
, size_t space_bitmap_size
);
601 void (*clear_fragments
) (void);
602 SgenFragment
* (*build_fragments_get_exclude_head
) (void);
603 void (*build_fragments_release_exclude_head
) (void);
604 void (*build_fragments_finish
) (SgenFragmentAllocator
*allocator
);
605 void (*init_nursery
) (SgenFragmentAllocator
*allocator
, char *start
, char *end
);
607 gboolean (*handle_gc_param
) (const char *opt
); /* Optional */
608 void (*print_gc_param_usage
) (void); /* Optional */
609 } SgenMinorCollector
;
611 extern SgenMinorCollector sgen_minor_collector
;
613 void sgen_simple_nursery_init (SgenMinorCollector
*collector
) MONO_INTERNAL
;
614 void sgen_split_nursery_init (SgenMinorCollector
*collector
) MONO_INTERNAL
;
616 typedef void (*sgen_cardtable_block_callback
) (mword start
, mword size
);
617 void sgen_major_collector_iterate_live_block_ranges (sgen_cardtable_block_callback callback
) MONO_INTERNAL
;
620 ITERATE_OBJECTS_SWEEP
= 1,
621 ITERATE_OBJECTS_NON_PINNED
= 2,
622 ITERATE_OBJECTS_PINNED
= 4,
623 ITERATE_OBJECTS_ALL
= ITERATE_OBJECTS_NON_PINNED
| ITERATE_OBJECTS_PINNED
,
624 ITERATE_OBJECTS_SWEEP_NON_PINNED
= ITERATE_OBJECTS_SWEEP
| ITERATE_OBJECTS_NON_PINNED
,
625 ITERATE_OBJECTS_SWEEP_PINNED
= ITERATE_OBJECTS_SWEEP
| ITERATE_OBJECTS_PINNED
,
626 ITERATE_OBJECTS_SWEEP_ALL
= ITERATE_OBJECTS_SWEEP
| ITERATE_OBJECTS_NON_PINNED
| ITERATE_OBJECTS_PINNED
627 } IterateObjectsFlags
;
629 typedef struct _SgenMajorCollector SgenMajorCollector
;
630 struct _SgenMajorCollector
{
632 gboolean is_concurrent
;
633 gboolean supports_cardtable
;
634 gboolean sweeps_lazily
;
637 * This is set to TRUE if the sweep for the last major
638 * collection has been completed.
640 gboolean
*have_swept
;
642 * This is set to TRUE by the sweep if the next major
643 * collection should be synchronous (for evacuation). For
644 * non-concurrent collectors, this should be NULL.
646 gboolean
*want_synchronous_collection
;
648 void* (*alloc_heap
) (mword nursery_size
, mword nursery_align
, int nursery_bits
);
649 gboolean (*is_object_live
) (char *obj
);
650 void* (*alloc_small_pinned_obj
) (MonoVTable
*vtable
, size_t size
, gboolean has_references
);
651 void* (*alloc_degraded
) (MonoVTable
*vtable
, size_t size
);
653 SgenObjectOperations major_ops
;
654 SgenObjectOperations major_concurrent_ops
;
656 void* (*alloc_object
) (MonoVTable
*vtable
, size_t size
, gboolean has_references
);
657 void (*free_pinned_object
) (char *obj
, size_t size
);
658 void (*iterate_objects
) (IterateObjectsFlags flags
, IterateObjectCallbackFunc callback
, void *data
);
659 void (*free_non_pinned_object
) (char *obj
, size_t size
);
660 void (*find_pin_queue_start_ends
) (SgenGrayQueue
*queue
);
661 void (*pin_objects
) (SgenGrayQueue
*queue
);
662 void (*pin_major_object
) (char *obj
, SgenGrayQueue
*queue
);
663 void (*scan_card_table
) (gboolean mod_union
, SgenGrayQueue
*queue
);
664 void (*iterate_live_block_ranges
) (sgen_cardtable_block_callback callback
);
665 void (*update_cardtable_mod_union
) (void);
666 void (*init_to_space
) (void);
667 void (*sweep
) (void);
668 void (*check_scan_starts
) (void);
669 void (*dump_heap
) (FILE *heap_dump_file
);
670 gint64 (*get_used_size
) (void);
671 void (*start_nursery_collection
) (void);
672 void (*finish_nursery_collection
) (void);
673 void (*start_major_collection
) (void);
674 void (*finish_major_collection
) (void);
675 void (*have_computed_minor_collection_allowance
) (void);
676 gboolean (*ptr_is_in_non_pinned_space
) (char *ptr
, char **start
);
677 gboolean (*obj_is_from_pinned_alloc
) (char *obj
);
678 void (*report_pinned_memory_usage
) (void);
679 size_t (*get_num_major_sections
) (void);
680 gboolean (*handle_gc_param
) (const char *opt
);
681 void (*print_gc_param_usage
) (void);
682 gboolean (*is_worker_thread
) (MonoNativeThreadId thread
);
683 void (*post_param_init
) (SgenMajorCollector
*collector
);
684 void* (*alloc_worker_data
) (void);
685 void (*init_worker_thread
) (void *data
);
686 void (*reset_worker_data
) (void *data
);
687 gboolean (*is_valid_object
) (char *object
);
688 MonoVTable
* (*describe_pointer
) (char *pointer
);
689 guint8
* (*get_cardtable_mod_union_for_object
) (char *object
);
690 long long (*get_and_reset_num_major_objects_marked
) (void);
691 void (*count_cards
) (long long *num_total_cards
, long long *num_marked_cards
);
694 extern SgenMajorCollector major_collector
;
696 void sgen_marksweep_init (SgenMajorCollector
*collector
) MONO_INTERNAL
;
697 void sgen_marksweep_fixed_init (SgenMajorCollector
*collector
) MONO_INTERNAL
;
698 void sgen_marksweep_par_init (SgenMajorCollector
*collector
) MONO_INTERNAL
;
699 void sgen_marksweep_fixed_par_init (SgenMajorCollector
*collector
) MONO_INTERNAL
;
700 void sgen_marksweep_conc_init (SgenMajorCollector
*collector
) MONO_INTERNAL
;
701 SgenMajorCollector
* sgen_get_major_collector (void) MONO_INTERNAL
;
704 typedef struct _SgenRemeberedSet
{
705 void (*wbarrier_set_field
) (MonoObject
*obj
, gpointer field_ptr
, MonoObject
* value
);
706 void (*wbarrier_set_arrayref
) (MonoArray
*arr
, gpointer slot_ptr
, MonoObject
* value
);
707 void (*wbarrier_arrayref_copy
) (gpointer dest_ptr
, gpointer src_ptr
, int count
);
708 void (*wbarrier_value_copy
) (gpointer dest
, gpointer src
, int count
, MonoClass
*klass
);
709 void (*wbarrier_object_copy
) (MonoObject
* obj
, MonoObject
*src
);
710 void (*wbarrier_generic_nostore
) (gpointer ptr
);
711 void (*record_pointer
) (gpointer ptr
);
713 void (*finish_scan_remsets
) (void *start_nursery
, void *end_nursery
, SgenGrayQueue
*queue
);
715 void (*prepare_for_major_collection
) (void);
717 void (*finish_minor_collection
) (void);
718 gboolean (*find_address
) (char *addr
);
719 gboolean (*find_address_with_cards
) (char *cards_start
, guint8
*cards
, char *addr
);
722 SgenRemeberedSet
*sgen_get_remset (void) MONO_INTERNAL
;
724 static mword
/*__attribute__((noinline)) not sure if this hint is a good idea*/
725 slow_object_get_size (MonoVTable
*vtable
, MonoObject
* o
)
727 MonoClass
*klass
= vtable
->klass
;
730 * We depend on mono_string_length_fast and
731 * mono_array_length_fast not using the object's vtable.
733 if (klass
== mono_defaults
.string_class
) {
734 return offsetof (MonoString
, chars
) + 2 * mono_string_length_fast ((MonoString
*) o
) + 2;
735 } else if (klass
->rank
) {
736 MonoArray
*array
= (MonoArray
*)o
;
737 size_t size
= sizeof (MonoArray
) + klass
->sizes
.element_size
* mono_array_length_fast (array
);
738 if (G_UNLIKELY (array
->bounds
)) {
739 size
+= sizeof (mono_array_size_t
) - 1;
740 size
&= ~(sizeof (mono_array_size_t
) - 1);
741 size
+= sizeof (MonoArrayBounds
) * klass
->rank
;
745 /* from a created object: the class must be inited already */
746 return klass
->instance_size
;
751 sgen_vtable_get_descriptor (MonoVTable
*vtable
)
753 return (mword
)vtable
->gc_descr
;
757 sgen_obj_get_descriptor (char *obj
)
759 MonoVTable
*vtable
= ((MonoObject
*)obj
)->vtable
;
760 SGEN_ASSERT (0, !SGEN_POINTER_IS_TAGGED_1_OR_2 (vtable
), "Object can't be tagged");
761 return sgen_vtable_get_descriptor (vtable
);
765 sgen_obj_get_descriptor_safe (char *obj
)
767 MonoVTable
*vtable
= (MonoVTable
*)SGEN_LOAD_VTABLE (obj
);
768 return sgen_vtable_get_descriptor (vtable
);
772 * This function can be called on an object whose first word, the
773 * vtable field, is not intact. This is necessary for the parallel
777 sgen_par_object_get_size (MonoVTable
*vtable
, MonoObject
* o
)
779 mword descr
= (mword
)vtable
->gc_descr
;
780 mword type
= descr
& 0x7;
782 if (type
== DESC_TYPE_RUN_LENGTH
|| type
== DESC_TYPE_SMALL_BITMAP
) {
783 mword size
= descr
& 0xfff8;
784 if (size
== 0) /* This is used to encode a string */
785 return offsetof (MonoString
, chars
) + 2 * mono_string_length_fast ((MonoString
*) o
) + 2;
787 } else if (type
== DESC_TYPE_VECTOR
) {
788 int element_size
= ((descr
) >> VECTOR_ELSIZE_SHIFT
) & MAX_ELEMENT_SIZE
;
789 MonoArray
*array
= (MonoArray
*)o
;
790 size_t size
= sizeof (MonoArray
) + element_size
* mono_array_length_fast (array
);
792 if (descr
& VECTOR_KIND_ARRAY
) {
793 size
+= sizeof (mono_array_size_t
) - 1;
794 size
&= ~(sizeof (mono_array_size_t
) - 1);
795 size
+= sizeof (MonoArrayBounds
) * vtable
->klass
->rank
;
800 return slow_object_get_size (vtable
, o
);
804 sgen_safe_object_get_size (MonoObject
*obj
)
808 if ((forwarded
= SGEN_OBJECT_IS_FORWARDED (obj
)))
809 obj
= (MonoObject
*)forwarded
;
811 return sgen_par_object_get_size ((MonoVTable
*)SGEN_LOAD_VTABLE (obj
), obj
);
814 const char* sgen_safe_name (void* obj
) MONO_INTERNAL
;
816 gboolean
sgen_object_is_live (void *obj
) MONO_INTERNAL
;
818 void sgen_init_fin_weak_hash (void) MONO_INTERNAL
;
820 gboolean
sgen_need_bridge_processing (void) MONO_INTERNAL
;
821 void sgen_bridge_reset_data (void) MONO_INTERNAL
;
822 void sgen_bridge_processing_stw_step (void) MONO_INTERNAL
;
823 void sgen_bridge_processing_finish (int generation
) MONO_INTERNAL
;
824 void sgen_register_test_bridge_callbacks (const char *bridge_class_name
) MONO_INTERNAL
;
825 gboolean
sgen_is_bridge_object (MonoObject
*obj
) MONO_INTERNAL
;
826 MonoGCBridgeObjectKind
sgen_bridge_class_kind (MonoClass
*klass
) MONO_INTERNAL
;
827 void sgen_mark_bridge_object (MonoObject
*obj
) MONO_INTERNAL
;
828 void sgen_bridge_register_finalized_object (MonoObject
*object
) MONO_INTERNAL
;
829 void sgen_bridge_describe_pointer (MonoObject
*object
) MONO_INTERNAL
;
831 void sgen_mark_togglerefs (char *start
, char *end
, ScanCopyContext ctx
) MONO_INTERNAL
;
832 void sgen_clear_togglerefs (char *start
, char *end
, ScanCopyContext ctx
) MONO_INTERNAL
;
834 void sgen_process_togglerefs (void) MONO_INTERNAL
;
835 void sgen_register_test_toggleref_callback (void) MONO_INTERNAL
;
837 gboolean
sgen_is_bridge_object (MonoObject
*obj
) MONO_INTERNAL
;
838 void sgen_mark_bridge_object (MonoObject
*obj
) MONO_INTERNAL
;
840 gboolean
sgen_bridge_handle_gc_debug (const char *opt
) MONO_INTERNAL
;
841 void sgen_bridge_print_gc_debug_usage (void) MONO_INTERNAL
;
844 void (*reset_data
) (void);
845 void (*processing_stw_step
) (void);
846 void (*processing_build_callback_data
) (int generation
);
847 void (*processing_after_callback
) (int generation
);
848 MonoGCBridgeObjectKind (*class_kind
) (MonoClass
*class);
849 void (*register_finalized_object
) (MonoObject
*object
);
850 void (*describe_pointer
) (MonoObject
*object
);
851 void (*enable_accounting
) (void);
852 void (*set_dump_prefix
) (const char *prefix
);
855 * These are set by processing_build_callback_data().
858 MonoGCBridgeSCC
**api_sccs
;
861 MonoGCBridgeXRef
*api_xrefs
;
862 } SgenBridgeProcessor
;
864 void sgen_old_bridge_init (SgenBridgeProcessor
*collector
) MONO_INTERNAL
;
865 void sgen_new_bridge_init (SgenBridgeProcessor
*collector
) MONO_INTERNAL
;
866 void sgen_tarjan_bridge_init (SgenBridgeProcessor
*collector
) MONO_INTERNAL
;
867 void sgen_set_bridge_implementation (const char *name
) MONO_INTERNAL
;
868 void sgen_bridge_set_dump_prefix (const char *prefix
) MONO_INTERNAL
;
870 gboolean
sgen_compare_bridge_processor_results (SgenBridgeProcessor
*a
, SgenBridgeProcessor
*b
) MONO_INTERNAL
;
872 typedef mono_bool (*WeakLinkAlivePredicateFunc
) (MonoObject
*, void*);
874 void sgen_null_links_with_predicate (int generation
, WeakLinkAlivePredicateFunc predicate
, void *data
) MONO_INTERNAL
;
876 gboolean
sgen_gc_is_object_ready_for_finalization (void *object
) MONO_INTERNAL
;
877 void sgen_gc_lock (void) MONO_INTERNAL
;
878 void sgen_gc_unlock (void) MONO_INTERNAL
;
879 void sgen_gc_event_moves (void) MONO_INTERNAL
;
881 void sgen_queue_finalization_entry (MonoObject
*obj
) MONO_INTERNAL
;
882 const char* sgen_generation_name (int generation
) MONO_INTERNAL
;
884 void sgen_collect_bridge_objects (int generation
, ScanCopyContext ctx
) MONO_INTERNAL
;
885 void sgen_finalize_in_range (int generation
, ScanCopyContext ctx
) MONO_INTERNAL
;
886 void sgen_null_link_in_range (int generation
, gboolean before_finalization
, ScanCopyContext ctx
) MONO_INTERNAL
;
887 void sgen_null_links_for_domain (MonoDomain
*domain
, int generation
) MONO_INTERNAL
;
888 void sgen_remove_finalizers_for_domain (MonoDomain
*domain
, int generation
) MONO_INTERNAL
;
889 void sgen_process_fin_stage_entries (void) MONO_INTERNAL
;
890 void sgen_process_dislink_stage_entries (void) MONO_INTERNAL
;
891 void sgen_register_disappearing_link (MonoObject
*obj
, void **link
, gboolean track
, gboolean in_gc
) MONO_INTERNAL
;
893 gboolean
sgen_drain_gray_stack (int max_objs
, ScanCopyContext ctx
) MONO_INTERNAL
;
901 void sgen_pin_object (void *object
, SgenGrayQueue
*queue
) MONO_INTERNAL
;
902 void sgen_parallel_pin_or_update (void **ptr
, void *obj
, MonoVTable
*vt
, SgenGrayQueue
*queue
) MONO_INTERNAL
;
903 void sgen_set_pinned_from_failed_allocation (mword objsize
) MONO_INTERNAL
;
905 void sgen_ensure_free_space (size_t size
) MONO_INTERNAL
;
906 void sgen_perform_collection (size_t requested_size
, int generation_to_collect
, const char *reason
, gboolean wait_to_finish
) MONO_INTERNAL
;
907 gboolean
sgen_has_critical_method (void) MONO_INTERNAL
;
908 gboolean
sgen_is_critical_method (MonoMethod
*method
) MONO_INTERNAL
;
915 gboolean is_overflow
;
916 SGEN_TV_DECLARE (total_time
);
917 SGEN_TV_DECLARE (stw_time
);
918 SGEN_TV_DECLARE (bridge_time
);
921 int sgen_stop_world (int generation
) MONO_INTERNAL
;
922 int sgen_restart_world (int generation
, GGTimingInfo
*timing
) MONO_INTERNAL
;
923 void sgen_init_stw (void) MONO_INTERNAL
;
927 typedef struct _LOSObject LOSObject
;
930 mword size
; /* this is the object size, lowest bit used for pin/mark */
931 guint8
*cardtable_mod_union
; /* only used by the concurrent collector */
932 #if SIZEOF_VOID_P < 8
933 mword dummy
; /* to align object to sizeof (double) */
935 char data
[MONO_ZERO_LEN_ARRAY
];
938 extern LOSObject
*los_object_list
;
939 extern mword los_memory_usage
;
941 void sgen_los_free_object (LOSObject
*obj
) MONO_INTERNAL
;
942 void* sgen_los_alloc_large_inner (MonoVTable
*vtable
, size_t size
) MONO_INTERNAL
;
943 void sgen_los_sweep (void) MONO_INTERNAL
;
944 gboolean
sgen_ptr_is_in_los (char *ptr
, char **start
) MONO_INTERNAL
;
945 void sgen_los_iterate_objects (IterateObjectCallbackFunc cb
, void *user_data
) MONO_INTERNAL
;
946 void sgen_los_iterate_live_block_ranges (sgen_cardtable_block_callback callback
) MONO_INTERNAL
;
947 void sgen_los_scan_card_table (gboolean mod_union
, SgenGrayQueue
*queue
) MONO_INTERNAL
;
948 void sgen_los_update_cardtable_mod_union (void) MONO_INTERNAL
;
949 void sgen_los_count_cards (long long *num_total_cards
, long long *num_marked_cards
) MONO_INTERNAL
;
950 void sgen_major_collector_scan_card_table (SgenGrayQueue
*queue
) MONO_INTERNAL
;
951 gboolean
sgen_los_is_valid_object (char *object
) MONO_INTERNAL
;
952 gboolean
mono_sgen_los_describe_pointer (char *ptr
) MONO_INTERNAL
;
953 LOSObject
* sgen_los_header_for_object (char *data
) MONO_INTERNAL
;
954 mword
sgen_los_object_size (LOSObject
*obj
) MONO_INTERNAL
;
955 void sgen_los_pin_object (char *obj
) MONO_INTERNAL
;
956 void sgen_los_unpin_object (char *obj
) MONO_INTERNAL
;
957 gboolean
sgen_los_object_is_pinned (char *obj
) MONO_INTERNAL
;
960 /* nursery allocator */
962 void sgen_clear_nursery_fragments (void) MONO_INTERNAL
;
963 void sgen_nursery_allocator_prepare_for_pinning (void) MONO_INTERNAL
;
964 void sgen_nursery_allocator_set_nursery_bounds (char *nursery_start
, char *nursery_end
) MONO_INTERNAL
;
965 mword
sgen_build_nursery_fragments (GCMemSection
*nursery_section
, void **start
, size_t num_entries
, SgenGrayQueue
*unpin_queue
) MONO_INTERNAL
;
966 void sgen_init_nursery_allocator (void) MONO_INTERNAL
;
967 void sgen_nursery_allocator_init_heavy_stats (void) MONO_INTERNAL
;
968 void sgen_alloc_init_heavy_stats (void) MONO_INTERNAL
;
969 char* sgen_nursery_alloc_get_upper_alloc_bound (void) MONO_INTERNAL
;
970 void* sgen_nursery_alloc (size_t size
) MONO_INTERNAL
;
971 void* sgen_nursery_alloc_range (size_t size
, size_t min_size
, size_t *out_alloc_size
) MONO_INTERNAL
;
972 MonoVTable
* sgen_get_array_fill_vtable (void) MONO_INTERNAL
;
973 gboolean
sgen_can_alloc_size (size_t size
) MONO_INTERNAL
;
974 void sgen_nursery_retire_region (void *address
, ptrdiff_t size
) MONO_INTERNAL
;
976 void sgen_nursery_alloc_prepare_for_minor (void) MONO_INTERNAL
;
977 void sgen_nursery_alloc_prepare_for_major (void) MONO_INTERNAL
;
979 char* sgen_alloc_for_promotion (char *obj
, size_t objsize
, gboolean has_references
) MONO_INTERNAL
;
983 extern MonoNativeTlsKey thread_info_key
;
985 #ifdef HAVE_KW_THREAD
986 extern __thread SgenThreadInfo
*sgen_thread_info
;
987 extern __thread
char *stack_end
;
990 #ifdef HAVE_KW_THREAD
991 #define TLAB_ACCESS_INIT
992 #define IN_CRITICAL_REGION sgen_thread_info->in_critical_region
994 #define TLAB_ACCESS_INIT SgenThreadInfo *__thread_info__ = mono_native_tls_get_value (thread_info_key)
995 #define IN_CRITICAL_REGION (__thread_info__->in_critical_region)
998 #ifndef DISABLE_CRITICAL_REGION
1000 #ifdef HAVE_KW_THREAD
1001 #define IN_CRITICAL_REGION sgen_thread_info->in_critical_region
1003 #define IN_CRITICAL_REGION (__thread_info__->in_critical_region)
1006 /* Enter must be visible before anything is done in the critical region. */
1007 #define ENTER_CRITICAL_REGION do { mono_atomic_store_acquire (&IN_CRITICAL_REGION, 1); } while (0)
1009 /* Exit must make sure all critical regions stores are visible before it signal the end of the region.
1010 * We don't need to emit a full barrier since we
1012 #define EXIT_CRITICAL_REGION do { mono_atomic_store_release (&IN_CRITICAL_REGION, 0); } while (0)
1016 #ifdef HAVE_KW_THREAD
1018 #define EMIT_TLS_ACCESS_NEXT_ADDR(mb) do { \
1019 mono_mb_emit_byte ((mb), MONO_CUSTOM_PREFIX); \
1020 mono_mb_emit_byte ((mb), CEE_MONO_TLS); \
1021 mono_mb_emit_i4 ((mb), TLS_KEY_SGEN_TLAB_NEXT_ADDR); \
1024 #define EMIT_TLS_ACCESS_TEMP_END(mb) do { \
1025 mono_mb_emit_byte ((mb), MONO_CUSTOM_PREFIX); \
1026 mono_mb_emit_byte ((mb), CEE_MONO_TLS); \
1027 mono_mb_emit_i4 ((mb), TLS_KEY_SGEN_TLAB_TEMP_END); \
1032 #if defined(__APPLE__) || defined (HOST_WIN32)
1033 #define EMIT_TLS_ACCESS_NEXT_ADDR(mb) do { \
1034 mono_mb_emit_byte ((mb), MONO_CUSTOM_PREFIX); \
1035 mono_mb_emit_byte ((mb), CEE_MONO_TLS); \
1036 mono_mb_emit_i4 ((mb), TLS_KEY_SGEN_THREAD_INFO); \
1037 mono_mb_emit_icon ((mb), MONO_STRUCT_OFFSET (SgenThreadInfo, tlab_next_addr)); \
1038 mono_mb_emit_byte ((mb), CEE_ADD); \
1039 mono_mb_emit_byte ((mb), CEE_LDIND_I); \
1042 #define EMIT_TLS_ACCESS_TEMP_END(mb) do { \
1043 mono_mb_emit_byte ((mb), MONO_CUSTOM_PREFIX); \
1044 mono_mb_emit_byte ((mb), CEE_MONO_TLS); \
1045 mono_mb_emit_i4 ((mb), TLS_KEY_SGEN_THREAD_INFO); \
1046 mono_mb_emit_icon ((mb), MONO_STRUCT_OFFSET (SgenThreadInfo, tlab_temp_end)); \
1047 mono_mb_emit_byte ((mb), CEE_ADD); \
1048 mono_mb_emit_byte ((mb), CEE_LDIND_I); \
1052 #define EMIT_TLS_ACCESS_NEXT_ADDR(mb) do { g_error ("sgen is not supported when using --with-tls=pthread.\n"); } while (0)
1053 #define EMIT_TLS_ACCESS_TEMP_END(mb) do { g_error ("sgen is not supported when using --with-tls=pthread.\n"); } while (0)
1060 extern GCMemSection
*nursery_section
;
1061 extern guint32 collect_before_allocs
;
1062 extern guint32 verify_before_allocs
;
1063 extern gboolean has_per_allocation_action
;
1064 extern size_t degraded_mode
;
1065 extern int default_nursery_size
;
1066 extern guint32 tlab_size
;
1067 extern NurseryClearPolicy nursery_clear_policy
;
1068 extern gboolean sgen_try_free_some_memory
;
1070 extern LOCK_DECLARE (gc_mutex
);
1072 extern int do_pin_stats
;
1074 /* Nursery helpers. */
1077 sgen_set_nursery_scan_start (char *p
)
1079 size_t idx
= (p
- (char*)nursery_section
->data
) / SGEN_SCAN_START_SIZE
;
1080 char *old
= nursery_section
->scan_starts
[idx
];
1081 if (!old
|| old
> p
)
1082 nursery_section
->scan_starts
[idx
] = p
;
1086 /* Object Allocation */
1094 } SgenAllocatorType
;
1096 void sgen_init_tlab_info (SgenThreadInfo
* info
);
1097 void sgen_clear_tlabs (void);
1098 void sgen_set_use_managed_allocator (gboolean flag
);
1099 gboolean
sgen_is_managed_allocator (MonoMethod
*method
);
1100 gboolean
sgen_has_managed_allocator (void);
1104 void sgen_check_consistency (void);
1105 void sgen_check_mod_union_consistency (void);
1106 void sgen_check_major_refs (void);
1107 void sgen_check_whole_heap (gboolean allow_missing_pinning
);
1108 void sgen_check_whole_heap_stw (void) MONO_INTERNAL
;
1109 void sgen_check_objref (char *obj
);
1110 void sgen_check_major_heap_marked (void) MONO_INTERNAL
;
1111 void sgen_check_nursery_objects_pinned (gboolean pinned
) MONO_INTERNAL
;
1112 void sgen_scan_for_registered_roots_in_domain (MonoDomain
*domain
, int root_type
) MONO_INTERNAL
;
1113 void sgen_check_for_xdomain_refs (void) MONO_INTERNAL
;
1115 void mono_gc_scan_for_specific_ref (MonoObject
*key
, gboolean precise
) MONO_INTERNAL
;
1117 /* Write barrier support */
1120 * This causes the compile to extend the liveness of 'v' till the call to dummy_use
1123 sgen_dummy_use (gpointer v
) {
1124 #if defined(__GNUC__)
1125 __asm__
volatile ("" : "=r"(v
) : "r"(v
));
1126 #elif defined(_MSC_VER)
1127 static volatile gpointer ptr
;
1130 #error "Implement sgen_dummy_use for your compiler"
1134 /* Environment variable parsing */
1136 #define MONO_GC_PARAMS_NAME "MONO_GC_PARAMS"
1137 #define MONO_GC_DEBUG_NAME "MONO_GC_DEBUG"
1139 gboolean
sgen_parse_environment_string_extract_number (const char *str
, size_t *out
) MONO_INTERNAL
;
1140 void sgen_env_var_error (const char *env_var
, const char *fallback
, const char *description_format
, ...) MONO_INTERNAL
;
1144 void sgen_qsort (void *base
, size_t nel
, size_t width
, int (*compar
) (const void*, const void*)) MONO_INTERNAL
;
1145 gint64
sgen_timestamp (void) MONO_INTERNAL
;
1147 #endif /* HAVE_SGEN_GC */
1149 #endif /* __MONO_SGENGC_H__ */