+gsize* mono_sgen_get_complex_descriptor (GCVTable *vt) MONO_INTERNAL;
+
+#define OBJ_COMPLEX_FOREACH_PTR(vt,obj) do { \
+ /* there are pointers */ \
+ void **_objptr = (void**)(obj); \
+ gsize *bitmap_data = mono_sgen_get_complex_descriptor ((vt)); \
+ int bwords = (*bitmap_data) - 1; \
+ void **start_run = _objptr; \
+ bitmap_data++; \
+ if (0) { \
+ MonoObject *myobj = (MonoObject*)obj; \
+ g_print ("found %d at %p (0x%zx): %s.%s\n", bwords, (obj), (vt)->desc, myobj->vtable->klass->name_space, myobj->vtable->klass->name); \
+ } \
+ while (bwords-- > 0) { \
+ gsize _bmap = *bitmap_data++; \
+ _objptr = start_run; \
+ /*g_print ("bitmap: 0x%x/%d at %p\n", _bmap, bwords, _objptr);*/ \
+ while (_bmap) { \
+ if ((_bmap & 1)) { \
+ HANDLE_PTR (_objptr, (obj)); \
+ } \
+ _bmap >>= 1; \
+ ++_objptr; \
+ } \
+ start_run += GC_BITS_PER_WORD; \
+ } \
+ } while (0)
+
+/* this one is untested */
+#define OBJ_COMPLEX_ARR_FOREACH_PTR(vt,obj) do { \
+ /* there are pointers */ \
+ gsize *mbitmap_data = mono_sgen_get_complex_descriptor ((vt)); \
+ int mbwords = (*mbitmap_data++) - 1; \
+ int el_size = mono_array_element_size (vt->klass); \
+ char *e_start = (char*)(obj) + G_STRUCT_OFFSET (MonoArray, vector); \
+ char *e_end = e_start + el_size * mono_array_length_fast ((MonoArray*)(obj)); \
+ if (0) \
+ g_print ("found %d at %p (0x%zx): %s.%s\n", mbwords, (obj), (vt)->desc, vt->klass->name_space, vt->klass->name); \
+ while (e_start < e_end) { \
+ void **_objptr = (void**)e_start; \
+ gsize *bitmap_data = mbitmap_data; \
+ unsigned int bwords = mbwords; \
+ while (bwords-- > 0) { \
+ gsize _bmap = *bitmap_data++; \
+ void **start_run = _objptr; \
+ /*g_print ("bitmap: 0x%x\n", _bmap);*/ \
+ while (_bmap) { \
+ if ((_bmap & 1)) { \
+ HANDLE_PTR (_objptr, (obj)); \
+ } \
+ _bmap >>= 1; \
+ ++_objptr; \
+ } \
+ _objptr = start_run + GC_BITS_PER_WORD; \
+ } \
+ e_start += el_size; \
+ } \
+ } while (0)
+
+#define OBJ_VECTOR_FOREACH_PTR(vt,obj) do { \
+ /* note: 0xffffc000 excludes DESC_TYPE_V_PTRFREE */ \
+ if ((vt)->desc & 0xffffc000) { \
+ int el_size = ((vt)->desc >> 3) & MAX_ELEMENT_SIZE; \
+ /* there are pointers */ \
+ int etype = (vt)->desc & 0xc000; \
+ if (etype == (DESC_TYPE_V_REFS << 14)) { \
+ void **p = (void**)((char*)(obj) + G_STRUCT_OFFSET (MonoArray, vector)); \
+ void **end_refs = (void**)((char*)p + el_size * mono_array_length_fast ((MonoArray*)(obj))); \
+ /* Note: this code can handle also arrays of struct with only references in them */ \
+ while (p < end_refs) { \
+ HANDLE_PTR (p, (obj)); \
+ ++p; \
+ } \
+ } else if (etype == DESC_TYPE_V_RUN_LEN << 14) { \
+ int offset = ((vt)->desc >> 16) & 0xff; \
+ int num_refs = ((vt)->desc >> 24) & 0xff; \
+ char *e_start = (char*)(obj) + G_STRUCT_OFFSET (MonoArray, vector); \
+ char *e_end = e_start + el_size * mono_array_length_fast ((MonoArray*)(obj)); \
+ while (e_start < e_end) { \
+ void **p = (void**)e_start; \
+ int i; \
+ p += offset; \
+ for (i = 0; i < num_refs; ++i) { \
+ HANDLE_PTR (p + i, (obj)); \
+ } \
+ e_start += el_size; \
+ } \
+ } else if (etype == DESC_TYPE_V_BITMAP << 14) { \
+ char *e_start = (char*)(obj) + G_STRUCT_OFFSET (MonoArray, vector); \
+ char *e_end = e_start + el_size * mono_array_length_fast ((MonoArray*)(obj)); \
+ while (e_start < e_end) { \
+ void **p = (void**)e_start; \
+ gsize _bmap = (vt)->desc >> 16; \
+ /* Note: there is no object header here to skip */ \
+ while (_bmap) { \
+ if ((_bmap & 1)) { \
+ HANDLE_PTR (p, (obj)); \
+ } \
+ _bmap >>= 1; \
+ ++p; \
+ } \
+ e_start += el_size; \
+ } \
+ } \
+ } \
+ } while (0)
+
+typedef struct _SgenInternalAllocator SgenInternalAllocator;
+
+#define SGEN_GRAY_QUEUE_SECTION_SIZE (128 - 3)
+
+/*
+ * This is a stack now instead of a queue, so the most recently added items are removed
+ * first, improving cache locality, and keeping the stack size manageable.
+ */
+typedef struct _GrayQueueSection GrayQueueSection;
+struct _GrayQueueSection {
+ int end;
+ GrayQueueSection *next;
+ char *objects [SGEN_GRAY_QUEUE_SECTION_SIZE];
+};
+
+typedef struct _SgenGrayQueue SgenGrayQueue;
+
+typedef void (*GrayQueueAllocPrepareFunc) (SgenGrayQueue*);
+
+struct _SgenGrayQueue {
+ SgenInternalAllocator *allocator;
+ GrayQueueSection *first;
+ GrayQueueSection *free_list;
+ int balance;
+ GrayQueueAllocPrepareFunc alloc_prepare_func;
+ void *alloc_prepare_data;
+};
+
+#if SGEN_MAX_DEBUG_LEVEL >= 9
+#define GRAY_OBJECT_ENQUEUE gray_object_enqueue
+#define GRAY_OBJECT_DEQUEUE(queue,o) ((o) = gray_object_dequeue ((queue)))
+#else
+#define GRAY_OBJECT_ENQUEUE(queue,o) do { \
+ if (G_UNLIKELY (!(queue)->first || (queue)->first->end == SGEN_GRAY_QUEUE_SECTION_SIZE)) \
+ mono_sgen_gray_object_enqueue ((queue), (o)); \
+ else \
+ (queue)->first->objects [(queue)->first->end++] = (o); \
+ } while (0)
+#define GRAY_OBJECT_DEQUEUE(queue,o) do { \
+ if (!(queue)->first) \
+ (o) = NULL; \
+ else if (G_UNLIKELY ((queue)->first->end == 1)) \
+ (o) = mono_sgen_gray_object_dequeue ((queue)); \
+ else \
+ (o) = (queue)->first->objects [--(queue)->first->end]; \
+ } while (0)
+#endif
+
+void mono_sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj) MONO_INTERNAL;
+char* mono_sgen_gray_object_dequeue (SgenGrayQueue *queue) MONO_INTERNAL;
+
+typedef void (*IterateObjectCallbackFunc) (char*, size_t, void*);
+
+void* mono_sgen_alloc_os_memory (size_t size, int activate) MONO_INTERNAL;
+void* mono_sgen_alloc_os_memory_aligned (mword size, mword alignment, gboolean activate) MONO_INTERNAL;
+void mono_sgen_free_os_memory (void *addr, size_t size) MONO_INTERNAL;
+
+int mono_sgen_thread_handshake (int signum) MONO_INTERNAL;
+SgenThreadInfo* mono_sgen_thread_info_lookup (ARCH_THREAD_TYPE id) MONO_INTERNAL;
+SgenThreadInfo** mono_sgen_get_thread_table (void) MONO_INTERNAL;
+void mono_sgen_wait_for_suspend_ack (int count) MONO_INTERNAL;
+
+gboolean mono_sgen_is_worker_thread (pthread_t thread) MONO_INTERNAL;
+
+void mono_sgen_update_heap_boundaries (mword low, mword high) MONO_INTERNAL;
+
+void mono_sgen_register_major_sections_alloced (int num_sections) MONO_INTERNAL;
+mword mono_sgen_get_minor_collection_allowance (void) MONO_INTERNAL;
+
+void mono_sgen_scan_area_with_callback (char *start, char *end, IterateObjectCallbackFunc callback, void *data) MONO_INTERNAL;
+void mono_sgen_check_section_scan_starts (GCMemSection *section) MONO_INTERNAL;
+
+/* Keep in sync with mono_sgen_dump_internal_mem_usage() in dump_heap()! */
+enum {
+ INTERNAL_MEM_MANAGED,
+ INTERNAL_MEM_PIN_QUEUE,
+ INTERNAL_MEM_FRAGMENT,
+ INTERNAL_MEM_SECTION,
+ INTERNAL_MEM_SCAN_STARTS,
+ INTERNAL_MEM_FIN_TABLE,
+ INTERNAL_MEM_FINALIZE_ENTRY,
+ INTERNAL_MEM_DISLINK_TABLE,
+ INTERNAL_MEM_DISLINK,
+ INTERNAL_MEM_ROOTS_TABLE,
+ INTERNAL_MEM_ROOT_RECORD,
+ INTERNAL_MEM_STATISTICS,
+ INTERNAL_MEM_REMSET,
+ INTERNAL_MEM_GRAY_QUEUE,
+ INTERNAL_MEM_STORE_REMSET,
+ INTERNAL_MEM_MS_TABLES,
+ INTERNAL_MEM_MS_BLOCK_INFO,
+ INTERNAL_MEM_EPHEMERON_LINK,
+ INTERNAL_MEM_WORKER_DATA,
+ INTERNAL_MEM_MAX
+};
+
+#define SGEN_INTERNAL_FREELIST_NUM_SLOTS 30
+
+struct _SgenInternalAllocator {
+ SgenPinnedChunk *chunk_list;
+ SgenPinnedChunk *free_lists [SGEN_INTERNAL_FREELIST_NUM_SLOTS];
+ void *delayed_free_lists [SGEN_INTERNAL_FREELIST_NUM_SLOTS];
+ long small_internal_mem_bytes [INTERNAL_MEM_MAX];
+};
+
+void mono_sgen_init_internal_allocator (void) MONO_INTERNAL;
+
+SgenInternalAllocator* mono_sgen_get_unmanaged_allocator (void) MONO_INTERNAL;
+
+const char* mono_sgen_internal_mem_type_name (int type) MONO_INTERNAL;
+void mono_sgen_report_internal_mem_usage (void) MONO_INTERNAL;
+void mono_sgen_report_internal_mem_usage_full (SgenInternalAllocator *alc) MONO_INTERNAL;
+void mono_sgen_dump_internal_mem_usage (FILE *heap_dump_file) MONO_INTERNAL;
+void mono_sgen_dump_section (GCMemSection *section, const char *type) MONO_INTERNAL;
+void mono_sgen_dump_occupied (char *start, char *end, char *section_start) MONO_INTERNAL;
+
+void mono_sgen_register_moved_object (void *obj, void *destination) MONO_INTERNAL;
+
+void mono_sgen_register_fixed_internal_mem_type (int type, size_t size) MONO_INTERNAL;
+
+void* mono_sgen_alloc_internal (int type) MONO_INTERNAL;
+void mono_sgen_free_internal (void *addr, int type) MONO_INTERNAL;
+
+void* mono_sgen_alloc_internal_dynamic (size_t size, int type) MONO_INTERNAL;
+void mono_sgen_free_internal_dynamic (void *addr, size_t size, int type) MONO_INTERNAL;
+
+void* mono_sgen_alloc_internal_fixed (SgenInternalAllocator *allocator, int type) MONO_INTERNAL;
+void mono_sgen_free_internal_fixed (SgenInternalAllocator *allocator, void *addr, int type) MONO_INTERNAL;
+
+void* mono_sgen_alloc_internal_full (SgenInternalAllocator *allocator, size_t size, int type) MONO_INTERNAL;
+void mono_sgen_free_internal_full (SgenInternalAllocator *allocator, void *addr, size_t size, int type) MONO_INTERNAL;
+
+void mono_sgen_free_internal_delayed (void *addr, int type, SgenInternalAllocator *thread_allocator) MONO_INTERNAL;
+
+void mono_sgen_debug_printf (int level, const char *format, ...) MONO_INTERNAL;
+
+gboolean mono_sgen_parse_environment_string_extract_number (const char *str, glong *out) MONO_INTERNAL;
+
+void mono_sgen_internal_scan_objects (SgenInternalAllocator *alc, IterateObjectCallbackFunc callback, void *callback_data) MONO_INTERNAL;
+void mono_sgen_internal_scan_pinned_objects (SgenInternalAllocator *alc, IterateObjectCallbackFunc callback, void *callback_data) MONO_INTERNAL;
+
+void** mono_sgen_find_optimized_pin_queue_area (void *start, void *end, int *num) MONO_INTERNAL;
+void mono_sgen_find_section_pin_queue_start_end (GCMemSection *section) MONO_INTERNAL;
+void mono_sgen_pin_objects_in_section (GCMemSection *section, SgenGrayQueue *queue) MONO_INTERNAL;
+
+void mono_sgen_pin_stats_register_object (char *obj, size_t size);
+
+void mono_sgen_add_to_global_remset (gpointer ptr) MONO_INTERNAL;
+
+typedef struct _SgenMajorCollector SgenMajorCollector;
+struct _SgenMajorCollector {
+ size_t section_size;
+ gboolean is_parallel;
+
+ void* (*alloc_heap) (mword nursery_size, mword nursery_align, int nursery_bits);
+ gboolean (*is_object_live) (char *obj);
+ void* (*alloc_small_pinned_obj) (size_t size, gboolean has_references);
+ void* (*alloc_degraded) (MonoVTable *vtable, size_t size);
+ void (*copy_or_mark_object) (void **obj_slot, SgenGrayQueue *queue);
+ void (*minor_scan_object) (char *start, SgenGrayQueue *queue);
+ char* (*minor_scan_vtype) (char *start, mword desc, char* from_start, char* from_end, SgenGrayQueue *queue);
+ void (*major_scan_object) (char *start, SgenGrayQueue *queue);
+ void (*copy_object) (void **obj_slot, SgenGrayQueue *queue);
+ void* (*alloc_object) (int size, gboolean has_references);
+ void (*free_pinned_object) (char *obj, size_t size);
+ void (*iterate_objects) (gboolean non_pinned, gboolean pinned, IterateObjectCallbackFunc callback, void *data);
+ void (*free_non_pinned_object) (char *obj, size_t size);
+ void (*find_pin_queue_start_ends) (SgenGrayQueue *queue);
+ void (*pin_objects) (SgenGrayQueue *queue);
+ void (*init_to_space) (void);
+ void (*sweep) (void);
+ void (*check_scan_starts) (void);
+ void (*dump_heap) (FILE *heap_dump_file);
+ gint64 (*get_used_size) (void);
+ void (*start_nursery_collection) (void);
+ void (*finish_nursery_collection) (void);
+ void (*finish_major_collection) (void);
+ gboolean (*ptr_is_in_non_pinned_space) (char *ptr);
+ gboolean (*obj_is_from_pinned_alloc) (char *obj);
+ void (*report_pinned_memory_usage) (void);
+ int (*get_num_major_sections) (void);
+ gboolean (*handle_gc_param) (const char *opt);
+ void (*print_gc_param_usage) (void);
+};
+
+void mono_sgen_marksweep_init (SgenMajorCollector *collector) MONO_INTERNAL;
+void mono_sgen_marksweep_fixed_init (SgenMajorCollector *collector) MONO_INTERNAL;
+void mono_sgen_marksweep_par_init (SgenMajorCollector *collector) MONO_INTERNAL;
+void mono_sgen_marksweep_fixed_par_init (SgenMajorCollector *collector) MONO_INTERNAL;
+void mono_sgen_copying_init (SgenMajorCollector *collector) MONO_INTERNAL;
+
+/*
+ * 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 guint
+mono_sgen_par_object_get_size (MonoVTable *vtable, MonoObject* o)
+{
+ MonoClass *klass = vtable->klass;
+ /*
+ * We depend on mono_string_length_fast and
+ * 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;
+ } else if (klass->rank) {
+ MonoArray *array = (MonoArray*)o;
+ size_t size = sizeof (MonoArray) + klass->sizes.element_size * mono_array_length_fast (array);
+ if (G_UNLIKELY (array->bounds)) {
+ size += sizeof (mono_array_size_t) - 1;
+ size &= ~(sizeof (mono_array_size_t) - 1);
+ size += sizeof (MonoArrayBounds) * klass->rank;
+ }
+ return size;
+ } else {
+ /* from a created object: the class must be inited already */
+ return klass->instance_size;
+ }
+}
+
+#define mono_sgen_safe_object_get_size(o) mono_sgen_par_object_get_size ((MonoVTable*)SGEN_LOAD_VTABLE ((o)), (o))
+
+#endif /* __MONO_SGENGC_H__ */