X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fsgen-gc.h;h=25015bd1ae664996e4f2bdd0aaac0279fd1d9928;hb=9ac4b5b7a7062fd0b3d26e3bd0c9d426be904fc3;hp=1af53effd8c1e1880c5c38b72951c8bf96b9d6a2;hpb=dc75a4a86e190c2728d1858bf399a9c7e1cc01dc;p=mono.git diff --git a/mono/metadata/sgen-gc.h b/mono/metadata/sgen-gc.h index 1af53effd8c..25015bd1ae6 100644 --- a/mono/metadata/sgen-gc.h +++ b/mono/metadata/sgen-gc.h @@ -34,7 +34,6 @@ typedef struct _SgenThreadInfo SgenThreadInfo; #ifdef HAVE_PTHREAD_H #include #endif -#include #include #include #include @@ -67,7 +66,6 @@ NurseryClearPolicy sgen_get_nursery_clear_policy (void) MONO_INTERNAL; #define SGEN_TV_DECLARE(name) gint64 name #define SGEN_TV_GETTIME(tv) tv = mono_100ns_ticks () #define SGEN_TV_ELAPSED(start,end) (int)((end-start)) -#define SGEN_TV_ELAPSED_MS(start,end) ((SGEN_TV_ELAPSED((start),(end)) + 5000) / 10000) #if !defined(__MACH__) && !MONO_MACH_ARCH_SUPPORTED && defined(HAVE_PTHREAD_KILL) #define SGEN_POSIX_STW 1 @@ -144,8 +142,8 @@ struct _GCMemSection { */ char **scan_starts; /* in major collections indexes in the pin_queue for objects that pin this section */ - void **pin_queue_start; - size_t pin_queue_num_entries; + size_t pin_queue_first_entry; + size_t pin_queue_last_entry; size_t num_scan_start; }; @@ -160,7 +158,6 @@ struct _GCMemSection { mono_mutex_lock (&gc_mutex); \ MONO_GC_LOCKED (); \ } while (0) -#define TRYLOCK_GC (mono_mutex_trylock (&gc_mutex) == 0) #define UNLOCK_GC do { sgen_gc_unlock (); } while (0) extern LOCK_DECLARE (sgen_interruption_mutex); @@ -190,14 +187,10 @@ extern LOCK_DECLARE (sgen_interruption_mutex); #endif #ifdef HEAVY_STATISTICS -#define HEAVY_STAT(x) x - -extern long long stat_objects_alloced_degraded; -extern long long stat_bytes_alloced_degraded; -extern long long stat_copy_object_called_major; -extern long long stat_objects_copied_major; -#else -#define HEAVY_STAT(x) +extern guint64 stat_objects_alloced_degraded; +extern guint64 stat_bytes_alloced_degraded; +extern guint64 stat_copy_object_called_major; +extern guint64 stat_objects_copied_major; #endif #define SGEN_ASSERT(level, a, ...) do { \ @@ -217,11 +210,6 @@ extern long long stat_objects_copied_major; mono_gc_printf (gc_debug_file, format, ##__VA_ARGS__); \ } } while (0) -#define SGEN_LOG_DO(level, fun) do { \ - if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) { \ - fun; \ -} } while (0) - extern int gc_debug_level; extern FILE* gc_debug_file; @@ -314,113 +302,67 @@ typedef struct { mword desc; } GCVTable; -/* these bits are set in the object vtable: we could merge them since an object can be - * either pinned or forwarded but not both. - * We store them in the vtable slot because the bits are used in the sync block for - * other purposes: if we merge them and alloc the sync blocks aligned to 8 bytes, we can change +/* + * We use the lowest three bits in the vtable pointer of objects to tag whether they're + * forwarded, pinned, and/or cemented. These are the valid states: + * + * | State | bits | + * |------------------+------+ + * | default | 000 | + * | forwarded | 001 | + * | pinned | 010 | + * | pinned, cemented | 110 | + * + * We store them in the vtable slot because the bits are used in the sync block for other + * purposes: if we merge them and alloc the sync blocks aligned to 8 bytes, we can change * this and use bit 3 in the syncblock (with the lower two bits both set for forwarded, that * would be an invalid combination for the monitor and hash code). - * The values are already shifted. - * The forwarding address is stored in the sync block. */ -#define SGEN_FORWARDED_BIT 1 -#define SGEN_PINNED_BIT 2 -#define SGEN_VTABLE_BITS_MASK 0x3 + +#include "sgen-tagged-pointer.h" + +#define SGEN_VTABLE_BITS_MASK SGEN_TAGGED_POINTER_MASK + +#define SGEN_POINTER_IS_TAGGED_FORWARDED(p) SGEN_POINTER_IS_TAGGED_1((p)) +#define SGEN_POINTER_TAG_FORWARDED(p) SGEN_POINTER_TAG_1((p)) + +#define SGEN_POINTER_IS_TAGGED_PINNED(p) SGEN_POINTER_IS_TAGGED_2((p)) +#define SGEN_POINTER_TAG_PINNED(p) SGEN_POINTER_TAG_2((p)) + +#define SGEN_POINTER_IS_TAGGED_CEMENTED(p) SGEN_POINTER_IS_TAGGED_4((p)) +#define SGEN_POINTER_TAG_CEMENTED(p) SGEN_POINTER_TAG_4((p)) + +#define SGEN_POINTER_UNTAG_VTABLE(p) SGEN_POINTER_UNTAG_ALL((p)) /* returns NULL if not forwarded, or the forwarded address */ -#define SGEN_OBJECT_IS_FORWARDED(obj) (((mword*)(obj))[0] & SGEN_FORWARDED_BIT ? (void*)(((mword*)(obj))[0] & ~SGEN_VTABLE_BITS_MASK) : NULL) -#define SGEN_OBJECT_IS_PINNED(obj) (((mword*)(obj))[0] & SGEN_PINNED_BIT) +#define SGEN_VTABLE_IS_FORWARDED(vtable) (SGEN_POINTER_IS_TAGGED_FORWARDED ((vtable)) ? SGEN_POINTER_UNTAG_VTABLE ((vtable)) : NULL) +#define SGEN_OBJECT_IS_FORWARDED(obj) (SGEN_VTABLE_IS_FORWARDED (((mword*)(obj))[0])) + +#define SGEN_VTABLE_IS_PINNED(vtable) SGEN_POINTER_IS_TAGGED_PINNED ((vtable)) +#define SGEN_OBJECT_IS_PINNED(obj) (SGEN_VTABLE_IS_PINNED (((mword*)(obj))[0])) + +#define SGEN_OBJECT_IS_CEMENTED(obj) (SGEN_POINTER_IS_TAGGED_CEMENTED (((mword*)(obj))[0])) /* set the forwarded address fw_addr for object obj */ #define SGEN_FORWARD_OBJECT(obj,fw_addr) do { \ - ((mword*)(obj))[0] = (mword)(fw_addr) | SGEN_FORWARDED_BIT; \ + *(void**)(obj) = SGEN_POINTER_TAG_FORWARDED ((fw_addr)); \ } while (0) #define SGEN_PIN_OBJECT(obj) do { \ - ((mword*)(obj))[0] |= SGEN_PINNED_BIT; \ + *(void**)(obj) = SGEN_POINTER_TAG_PINNED (*(void**)(obj)); \ } while (0) +#define SGEN_CEMENT_OBJECT(obj) do { \ + *(void**)(obj) = SGEN_POINTER_TAG_CEMENTED (*(void**)(obj)); \ + } while (0) +/* Unpins and uncements */ #define SGEN_UNPIN_OBJECT(obj) do { \ - ((mword*)(obj))[0] &= ~SGEN_PINNED_BIT; \ + *(void**)(obj) = SGEN_POINTER_UNTAG_VTABLE (*(void**)(obj)); \ } while (0) /* * Since we set bits in the vtable, use the macro to load it from the pointer to * an object that is potentially pinned. */ -#define SGEN_LOAD_VTABLE(addr) ((*(mword*)(addr)) & ~SGEN_VTABLE_BITS_MASK) - -static inline MONO_ALWAYS_INLINE void -GRAY_OBJECT_ENQUEUE (SgenGrayQueue *queue, char* obj) -{ -#if defined(SGEN_GRAY_OBJECT_ENQUEUE) || SGEN_MAX_DEBUG_LEVEL >= 9 - sgen_gray_object_enqueue (queue, obj); -#else - if (G_UNLIKELY (!queue->first || queue->cursor == GRAY_LAST_CURSOR_POSITION (queue->first))) { - sgen_gray_object_enqueue (queue, obj); - } else { - HEAVY_STAT (gc_stats.gray_queue_enqueue_fast_path ++); - - *++queue->cursor = obj; -#ifdef SGEN_HEAVY_BINARY_PROTOCOL - binary_protocol_gray_enqueue (queue, queue->cursor, obj); -#endif - } - - PREFETCH (obj); -#endif -} - -static inline MONO_ALWAYS_INLINE void -GRAY_OBJECT_DEQUEUE (SgenGrayQueue *queue, char** obj) -{ -#if defined(SGEN_GRAY_OBJECT_ENQUEUE) || SGEN_MAX_DEBUG_LEVEL >= 9 - *obj = sgen_gray_object_enqueue (queue); -#else - if (!queue->first) { - HEAVY_STAT (gc_stats.gray_queue_dequeue_fast_path ++); - - *obj = NULL; -#ifdef SGEN_HEAVY_BINARY_PROTOCOL - binary_protocol_gray_dequeue (queue, queue->cursor, *obj); -#endif - } else if (G_UNLIKELY (queue->cursor == GRAY_FIRST_CURSOR_POSITION (queue->first))) { - *obj = sgen_gray_object_dequeue (queue); - } else { - HEAVY_STAT (gc_stats.gray_queue_dequeue_fast_path ++); - - *obj = *queue->cursor--; -#ifdef SGEN_HEAVY_BINARY_PROTOCOL - binary_protocol_gray_dequeue (queue, queue->cursor + 1, *obj); -#endif - } -#endif -} - -#define SGEN_MAX_PARTIAL_OFFSET 1500 -/*FIXME:This works only because SGEN_MAX_PARTIAL_OFFSET is even*/ -#define GRAY_OBJECT_IS_PARTIAL(obj) ((mword)(obj) & 1) - -#define GRAY_PARTIAL_OBJECT_ENQUEUE(queue,o) do{ \ - GRAY_OBJECT_ENQUEUE(queue,(o)); \ - if( SGEN_OBJECT_IS_VECTOR_V_REFS((o)) && sgen_get_major_collector()->is_parallel){ \ - mword i; \ - for(i=SGEN_MAX_PARTIAL_OFFSET; i< mono_array_length_fast ((MonoArray*)(o)); i+=SGEN_MAX_PARTIAL_OFFSET){ \ - if (G_UNLIKELY (queue->cursor == GRAY_SECOND_TO_LAST_CURSOR_POSITION(queue->first))){ \ - queue->first->size = SGEN_GRAY_QUEUE_SECTION_SIZE -1;\ - sgen_gray_object_alloc_queue_section (queue); \ - } \ - GRAY_OBJECT_ENQUEUE(queue, (char*)i); \ - GRAY_OBJECT_ENQUEUE(queue, (char*)((mword)o|1)); \ - } \ - } \ -} while(0) -#define GRAY_PARTIAL_OBJECT_DEQUEUE(queue,o,offset) do{ \ - GRAY_OBJECT_DEQUEUE((queue),&(o)); \ - (offset) = NULL; \ - if(GRAY_OBJECT_IS_PARTIAL((o))){ \ - GRAY_OBJECT_DEQUEUE((queue),&(offset)); \ - o = (char*)((mword)(o) & (~1)); \ - } \ -} while(0) +#define SGEN_LOAD_VTABLE(addr) SGEN_POINTER_UNTAG_ALL (*(void**)(addr)) /* List of what each bit on of the vtable gc bits means. @@ -503,6 +445,7 @@ enum { INTERNAL_MEM_TOGGLEREF_DATA, INTERNAL_MEM_CARDTABLE_MOD_UNION, INTERNAL_MEM_BINARY_PROTOCOL, + INTERNAL_MEM_TEMPORARY, INTERNAL_MEM_MAX }; @@ -527,16 +470,14 @@ struct _ObjectList { }; typedef void (*CopyOrMarkObjectFunc) (void**, SgenGrayQueue*); -typedef void (*ScanObjectFunc) (char*, SgenGrayQueue*); +typedef void (*ScanObjectFunc) (char *obj, mword desc, SgenGrayQueue*); typedef void (*ScanVTypeFunc) (char*, mword desc, SgenGrayQueue* BINARY_PROTOCOL_ARG (size_t size)); -typedef void (*ScanWorkFunc) (char*, mword, SgenGrayQueue*); typedef struct { ScanObjectFunc scan_func; CopyOrMarkObjectFunc copy_func; SgenGrayQueue *queue; - ScanWorkFunc scan_work; } ScanCopyContext; void sgen_report_internal_mem_usage (void) MONO_INTERNAL; @@ -554,10 +495,6 @@ void sgen_free_internal (void *addr, int type) MONO_INTERNAL; void* sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure) MONO_INTERNAL; void sgen_free_internal_dynamic (void *addr, size_t size, int type) MONO_INTERNAL; -void** sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *num) MONO_INTERNAL; -void sgen_find_section_pin_queue_start_end (GCMemSection *section) MONO_INTERNAL; -void sgen_pin_objects_in_section (GCMemSection *section, ScanCopyContext ctx) MONO_INTERNAL; - void sgen_pin_stats_register_object (char *obj, size_t size); void sgen_pin_stats_register_global_remset (char *obj); void sgen_pin_stats_print_class_stats (void); @@ -566,7 +503,6 @@ void sgen_sort_addresses (void **array, size_t size) MONO_INTERNAL; void sgen_add_to_global_remset (gpointer ptr, gpointer obj) MONO_INTERNAL; int sgen_get_current_collection_generation (void) MONO_INTERNAL; -gboolean sgen_collection_is_parallel (void) MONO_INTERNAL; gboolean sgen_collection_is_concurrent (void) MONO_INTERNAL; gboolean sgen_concurrent_collection_in_progress (void) MONO_INTERNAL; @@ -574,7 +510,6 @@ typedef struct { CopyOrMarkObjectFunc copy_or_mark_object; ScanObjectFunc scan_object; ScanVTypeFunc scan_vtype; - ScanWorkFunc scan_work; /*FIXME add allocation function? */ } SgenObjectOperations; @@ -630,7 +565,7 @@ static inline gboolean sgen_nursery_is_to_space (char *object) { size_t idx = (object - sgen_nursery_start) >> SGEN_TO_SPACE_GRANULE_BITS; - size_t byte = idx / 8; + size_t byte = idx >> 3; size_t bit = idx & 0x7; 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 ()); @@ -664,10 +599,8 @@ typedef struct { gboolean is_split; char* (*alloc_for_promotion) (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references); - char* (*par_alloc_for_promotion) (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references); SgenObjectOperations serial_ops; - SgenObjectOperations parallel_ops; void (*prepare_to_space) (char *to_space_bitmap, size_t space_bitmap_size); void (*clear_fragments) (void); @@ -685,6 +618,27 @@ extern SgenMinorCollector sgen_minor_collector; void sgen_simple_nursery_init (SgenMinorCollector *collector) MONO_INTERNAL; void sgen_split_nursery_init (SgenMinorCollector *collector) MONO_INTERNAL; +/* Updating references */ + +#ifdef SGEN_CHECK_UPDATE_REFERENCE +static inline void +sgen_update_reference (void **p, void *o, gboolean allow_null) +{ + if (!allow_null) + SGEN_ASSERT (0, o, "Cannot update a reference with a NULL pointer"); + SGEN_ASSERT (0, !sgen_is_worker_thread (mono_native_thread_id_get ()), "Can't update a reference in the worker thread"); + *p = o; +} + +#define SGEN_UPDATE_REFERENCE_ALLOW_NULL(p,o) sgen_update_reference ((void**)(p), (void*)(o), TRUE) +#define SGEN_UPDATE_REFERENCE(p,o) sgen_update_reference ((void**)(p), (void*)(o), FALSE) +#else +#define SGEN_UPDATE_REFERENCE_ALLOW_NULL(p,o) (*(void**)(p) = (void*)(o)) +#define SGEN_UPDATE_REFERENCE(p,o) SGEN_UPDATE_REFERENCE_ALLOW_NULL ((p), (o)) +#endif + +/* Major collector */ + typedef void (*sgen_cardtable_block_callback) (mword start, mword size); void sgen_major_collector_iterate_live_block_ranges (sgen_cardtable_block_callback callback) MONO_INTERNAL; @@ -698,10 +652,15 @@ typedef enum { ITERATE_OBJECTS_SWEEP_ALL = ITERATE_OBJECTS_SWEEP | ITERATE_OBJECTS_NON_PINNED | ITERATE_OBJECTS_PINNED } IterateObjectsFlags; +typedef struct +{ + size_t num_scanned_objects; + size_t num_unique_scanned_objects; +} ScannedObjectCounts; + typedef struct _SgenMajorCollector SgenMajorCollector; struct _SgenMajorCollector { size_t section_size; - gboolean is_parallel; gboolean is_concurrent; gboolean supports_cardtable; gboolean sweeps_lazily; @@ -727,7 +686,6 @@ struct _SgenMajorCollector { SgenObjectOperations major_concurrent_ops; void* (*alloc_object) (MonoVTable *vtable, size_t size, gboolean has_references); - void* (*par_alloc_object) (MonoVTable *vtable, size_t size, gboolean has_references); void (*free_pinned_object) (char *obj, size_t size); void (*iterate_objects) (IterateObjectsFlags flags, IterateObjectCallbackFunc callback, void *data); void (*free_non_pinned_object) (char *obj, size_t size); @@ -745,7 +703,8 @@ struct _SgenMajorCollector { void (*start_nursery_collection) (void); void (*finish_nursery_collection) (void); void (*start_major_collection) (void); - void (*finish_major_collection) (void); + void (*finish_major_collection) (ScannedObjectCounts *counts); + gboolean (*drain_gray_stack) (ScanCopyContext ctx); void (*have_computed_minor_collection_allowance) (void); gboolean (*ptr_is_in_non_pinned_space) (char *ptr, char **start); gboolean (*obj_is_from_pinned_alloc) (char *obj); @@ -805,7 +764,7 @@ slow_object_get_size (MonoVTable *vtable, MonoObject* o) * mono_array_length_fast not using the object's vtable. */ if (klass == mono_defaults.string_class) { - return sizeof (MonoString) + 2 * mono_string_length_fast ((MonoString*) o) + 2; + return G_STRUCT_OFFSET (MonoString, chars) + 2 * mono_string_length_fast ((MonoString*) o) + 2; } else if (klass->rank) { MonoArray *array = (MonoArray*)o; size_t size = sizeof (MonoArray) + klass->sizes.element_size * mono_array_length_fast (array); @@ -821,22 +780,44 @@ slow_object_get_size (MonoVTable *vtable, MonoObject* o) } } +static inline mword +sgen_vtable_get_descriptor (MonoVTable *vtable) +{ + return (mword)vtable->gc_descr; +} + +static inline mword +sgen_obj_get_descriptor (char *obj) +{ + MonoVTable *vtable = ((MonoObject*)obj)->vtable; + SGEN_ASSERT (9, !SGEN_POINTER_IS_TAGGED_ANY (vtable), "Object can't be tagged"); + return sgen_vtable_get_descriptor (vtable); +} + +static inline mword +sgen_obj_get_descriptor_safe (char *obj) +{ + MonoVTable *vtable = (MonoVTable*)SGEN_LOAD_VTABLE (obj); + return sgen_vtable_get_descriptor (vtable); +} + /* * This function can be called on an object whose first word, the * vtable field, is not intact. This is necessary for the parallel * collector. */ -static inline mword +static MONO_NEVER_INLINE mword sgen_par_object_get_size (MonoVTable *vtable, MonoObject* o) { mword descr = (mword)vtable->gc_descr; - mword type = descr & 0x7; + mword type = descr & DESC_TYPE_MASK; - if (type == DESC_TYPE_RUN_LENGTH || type == DESC_TYPE_SMALL_BITMAP) { + if (type == DESC_TYPE_RUN_LENGTH || type == DESC_TYPE_SMALL_PTRFREE) { mword size = descr & 0xfff8; - if (size == 0) /* This is used to encode a string */ - return sizeof (MonoString) + 2 * mono_string_length_fast ((MonoString*) o) + 2; + SGEN_ASSERT (9, size >= sizeof (MonoObject), "Run length object size to small"); return size; + } else if (descr == SGEN_DESC_STRING) { + return G_STRUCT_OFFSET (MonoString, chars) + 2 * mono_string_length_fast ((MonoString*) o) + 2; } else if (type == DESC_TYPE_VECTOR) { int element_size = ((descr) >> VECTOR_ELSIZE_SHIFT) & MAX_ELEMENT_SIZE; MonoArray *array = (MonoArray*)o; @@ -864,6 +845,22 @@ sgen_safe_object_get_size (MonoObject *obj) return sgen_par_object_get_size ((MonoVTable*)SGEN_LOAD_VTABLE (obj), obj); } +/* + * This variant guarantees to return the exact size of the object + * before alignment. Needed for canary support. + */ +static inline guint +sgen_safe_object_get_size_unaligned (MonoObject *obj) +{ + char *forwarded; + + if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) { + obj = (MonoObject*)forwarded; + } + + return slow_object_get_size ((MonoVTable*)SGEN_LOAD_VTABLE (obj), obj); +} + const char* sgen_safe_name (void* obj) MONO_INTERNAL; gboolean sgen_object_is_live (void *obj) MONO_INTERNAL; @@ -943,8 +940,7 @@ void sgen_process_fin_stage_entries (void) MONO_INTERNAL; void sgen_process_dislink_stage_entries (void) MONO_INTERNAL; void sgen_register_disappearing_link (MonoObject *obj, void **link, gboolean track, gboolean in_gc) MONO_INTERNAL; -gboolean sgen_drain_gray_stack (ScanCopyContext ctx) MONO_INTERNAL; -gboolean sgen_drain_gray_stack_work_item(int max_objs, ScanCopyContext ctx) MONO_INTERNAL; +gboolean sgen_drain_gray_stack (int max_objs, ScanCopyContext ctx) MONO_INTERNAL; enum { SPACE_NURSERY, @@ -1016,7 +1012,7 @@ gboolean sgen_los_object_is_pinned (char *obj) MONO_INTERNAL; void sgen_clear_nursery_fragments (void) MONO_INTERNAL; void sgen_nursery_allocator_prepare_for_pinning (void) MONO_INTERNAL; void sgen_nursery_allocator_set_nursery_bounds (char *nursery_start, char *nursery_end) MONO_INTERNAL; -mword sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_t num_entries, SgenGrayQueue *unpin_queue) MONO_INTERNAL; +mword sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpin_queue) MONO_INTERNAL; void sgen_init_nursery_allocator (void) MONO_INTERNAL; void sgen_nursery_allocator_init_heavy_stats (void) MONO_INTERNAL; void sgen_alloc_init_heavy_stats (void) MONO_INTERNAL; @@ -1031,7 +1027,6 @@ void sgen_nursery_alloc_prepare_for_minor (void) MONO_INTERNAL; void sgen_nursery_alloc_prepare_for_major (void) MONO_INTERNAL; char* sgen_alloc_for_promotion (char *obj, size_t objsize, gboolean has_references) MONO_INTERNAL; -char* sgen_par_alloc_for_promotion (char *obj, size_t objsize, gboolean has_references) MONO_INTERNAL; /* TLS Data */ @@ -1162,7 +1157,7 @@ void sgen_check_major_refs (void); void sgen_check_whole_heap (gboolean allow_missing_pinning); void sgen_check_whole_heap_stw (void) MONO_INTERNAL; void sgen_check_objref (char *obj); -void sgen_check_major_heap_marked (void) MONO_INTERNAL; +void sgen_check_heap_marked (gboolean nursery_must_be_pinned) MONO_INTERNAL; void sgen_check_nursery_objects_pinned (gboolean pinned) MONO_INTERNAL; void sgen_scan_for_registered_roots_in_domain (MonoDomain *domain, int root_type) MONO_INTERNAL; void sgen_check_for_xdomain_refs (void) MONO_INTERNAL; @@ -1199,6 +1194,37 @@ void sgen_env_var_error (const char *env_var, const char *fallback, const char * void sgen_qsort (void *base, size_t nel, size_t width, int (*compar) (const void*, const void*)) MONO_INTERNAL; gint64 sgen_timestamp (void) MONO_INTERNAL; +/* + * Canary (guard word) support + * Notes: + * - CANARY_SIZE must be multiple of word size in bytes + * - Canary space is not included on checks against SGEN_MAX_SMALL_OBJ_SIZE + */ + +gboolean nursery_canaries_enabled (void) MONO_INTERNAL; + +#define CANARY_SIZE 8 +#define CANARY_STRING "koupepia" + +#define CANARIFY_SIZE(size) if (nursery_canaries_enabled ()) { \ + size = size + CANARY_SIZE; \ + } + +#define CANARIFY_ALLOC(addr,size) if (nursery_canaries_enabled ()) { \ + memcpy ((char*) (addr) + (size), CANARY_STRING, CANARY_SIZE); \ + } + +#define CANARY_VALID(addr) (strncmp ((char*) (addr), CANARY_STRING, CANARY_SIZE) == 0) + +#define CHECK_CANARY_FOR_OBJECT(addr) if (nursery_canaries_enabled ()) { \ + char* canary_ptr = (char*) (addr) + sgen_safe_object_get_size_unaligned ((MonoObject *) (addr)); \ + if (!CANARY_VALID(canary_ptr)) { \ + char canary_copy[CANARY_SIZE +1]; \ + strncpy (canary_copy, canary_ptr, CANARY_SIZE); \ + canary_copy[CANARY_SIZE] = 0; \ + g_error ("CORRUPT CANARY:\naddr->%p\ntype->%s\nexcepted->'%s'\nfound->'%s'\n", (char*) addr, ((MonoObject*)addr)->vtable->klass->name, CANARY_STRING, canary_copy); \ + } } + #endif /* HAVE_SGEN_GC */ #endif /* __MONO_SGENGC_H__ */