Explorar el Código

Merge branch 'selectable-major'

Mark Probst hace 15 años
padre
commit
0a1d58da93

+ 2 - 1
mono/metadata/Makefile.am

@@ -64,7 +64,6 @@ sgen_sources = \
 	sgen-gray.c	\
 	sgen-pinning.c	\
 	sgen-pinning-stats.c	\
-	sgen-marksweep.c		\
 	sgen-los.c				\
 	sgen-protocol.c
 
@@ -168,6 +167,8 @@ libmonoruntime_la_SOURCES = \
 	sgen-os-mach.c		\
 	sgen-gc.c		\
 	sgen-internal.c		\
+	sgen-marksweep.c	\
+	sgen-major-copying.c	\
 	sgen-gc.h		\
 	sgen-archdep.h		\
 	sgen-scan-object.h	\

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 76 - 649
mono/metadata/sgen-gc.c


+ 470 - 0
mono/metadata/sgen-gc.h

@@ -31,6 +31,7 @@
 #include <signal.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/metadata/class-internals.h>
+#include <mono/metadata/object-internals.h>
 
 /* #define SGEN_PARALLEL_MARK */
 
@@ -40,8 +41,22 @@
  */
 //#define HEAVY_STATISTICS
 
+/*
+ * If this is set, the nursery is aligned to an address aligned to its size, ie.
+ * a 1MB nursery will be aligned to an address divisible by 1MB. This allows us to
+ * speed up ptr_in_nursery () checks which are very frequent. This requires the
+ * nursery size to be a compile time constant.
+ */
+#define SGEN_ALIGN_NURSERY 1
+
+//#define SGEN_BINARY_PROTOCOL
+
+#define SGEN_MAX_DEBUG_LEVEL 2
+
 #define THREAD_HASH_SIZE 11
 
+#define GC_BITS_PER_WORD (sizeof (mword) * 8)
+
 #define ARCH_THREAD_TYPE pthread_t
 #define ARCH_GET_THREAD pthread_self
 #define ARCH_THREAD_EQUALS(a,b) pthread_equal (a, b)
@@ -108,6 +123,51 @@ struct _SgenBlock {
 	unsigned char role;
 };
 
+/*
+ * The nursery section and the major copying collector's sections use
+ * this struct.
+ */
+typedef struct _GCMemSection GCMemSection;
+struct _GCMemSection {
+	SgenBlock block;
+	char *data;
+	mword size;
+	/* pointer where more data could be allocated if it fits */
+	char *next_data;
+	char *end_data;
+	/*
+	 * scan starts is an array of pointers to objects equally spaced in the allocation area
+	 * They let use quickly find pinned objects from pinning pointers.
+	 */
+	char **scan_starts;
+	/* in major collections indexes in the pin_queue for objects that pin this section */
+	void **pin_queue_start;
+	int pin_queue_num_entries;
+	unsigned short num_scan_start;
+	gboolean is_to_space;
+};
+
+#define SGEN_SIZEOF_GC_MEM_SECTION	((sizeof (GCMemSection) + 7) & ~7)
+
+/*
+ * to quickly find the head of an object pinned by a conservative
+ * address we keep track of the objects allocated for each
+ * SGEN_SCAN_START_SIZE memory chunk in the nursery or other memory
+ * sections. Larger values have less memory overhead and bigger
+ * runtime cost. 4-8 KB are reasonable values.
+ */
+#define SGEN_SCAN_START_SIZE (4096*2)
+
+/*
+ * Objects bigger then this go into the large object space.  This size
+ * has a few constraints.  It must fit into the major heap, which in
+ * the case of the copying collector means that it must fit into a
+ * pinned chunk.  It must also play well with the GC descriptors, some
+ * of which (DESC_TYPE_RUN_LENGTH, DESC_TYPE_SMALL_BITMAP) encode the
+ * object size.
+ */
+#define SGEN_MAX_SMALL_OBJ_SIZE 8000
+
 /* This is also the MAJOR_SECTION_SIZE for the copying major
    collector */
 #define SGEN_PINNED_CHUNK_SIZE	(128 * 1024)
@@ -153,6 +213,11 @@ const static int restart_signal_num = SIGXCPU;
 
 #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)
 #endif
@@ -162,6 +227,328 @@ const static int restart_signal_num = SIGXCPU;
 
 #define SGEN_ALIGN_UP(s)		(((s)+(SGEN_ALLOC_ALIGN-1)) & ~(SGEN_ALLOC_ALIGN-1))
 
+#ifdef SGEN_ALIGN_NURSERY
+#define SGEN_PTR_IN_NURSERY(p,bits,start,end)	(((mword)(p) & ~((1 << (bits)) - 1)) == (mword)(start))
+#else
+#define SGEN_PTR_IN_NURSERY(p,bits,start,end)	((char*)(p) >= (start) && (char*)(p) < (end))
+#endif
+
+/* Structure that corresponds to a MonoVTable: desc is a mword so requires
+ * no cast from a pointer to an integer
+ */
+typedef struct {
+	MonoClass *klass;
+	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
+ * 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
+
+/* 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)
+
+/* 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; \
+	} while (0)
+#define SGEN_PIN_OBJECT(obj) do {	\
+		((mword*)(obj))[0] |= SGEN_PINNED_BIT;	\
+	} while (0)
+#define SGEN_UNPIN_OBJECT(obj) do {	\
+		((mword*)(obj))[0] &= ~SGEN_PINNED_BIT;	\
+	} 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)
+
+/*
+ * ######################################################################
+ * ########  GC descriptors
+ * ######################################################################
+ * Used to quickly get the info the GC needs about an object: size and
+ * where the references are held.
+ */
+#define OBJECT_HEADER_WORDS (sizeof(MonoObject)/sizeof(gpointer))
+#define LOW_TYPE_BITS 3
+#define SMALL_BITMAP_SHIFT 16
+#define SMALL_BITMAP_SIZE (GC_BITS_PER_WORD - SMALL_BITMAP_SHIFT)
+#define VECTOR_INFO_SHIFT 14
+#define VECTOR_ELSIZE_SHIFT 3
+#define LARGE_BITMAP_SIZE (GC_BITS_PER_WORD - LOW_TYPE_BITS)
+#define MAX_ELEMENT_SIZE 0x3ff
+#define VECTOR_SUBTYPE_PTRFREE (DESC_TYPE_V_PTRFREE << VECTOR_INFO_SHIFT)
+#define VECTOR_SUBTYPE_REFS    (DESC_TYPE_V_REFS << VECTOR_INFO_SHIFT)
+#define VECTOR_SUBTYPE_RUN_LEN (DESC_TYPE_V_RUN_LEN << VECTOR_INFO_SHIFT)
+#define VECTOR_SUBTYPE_BITMAP  (DESC_TYPE_V_BITMAP << VECTOR_INFO_SHIFT)
+
+/* objects are aligned to 8 bytes boundaries
+ * A descriptor is a pointer in MonoVTable, so 32 or 64 bits of size.
+ * The low 3 bits define the type of the descriptor. The other bits
+ * depend on the type.
+ * As a general rule the 13 remaining low bits define the size, either
+ * of the whole object or of the elements in the arrays. While for objects
+ * the size is already in bytes, for arrays we need to shift, because
+ * array elements might be smaller than 8 bytes. In case of arrays, we
+ * use two bits to describe what the additional high bits represents,
+ * so the default behaviour can handle element sizes less than 2048 bytes.
+ * The high 16 bits, if 0 it means the object is pointer-free.
+ * This design should make it easy and fast to skip over ptr-free data.
+ * The first 4 types should cover >95% of the objects.
+ * Note that since the size of objects is limited to 64K, larger objects
+ * will be allocated in the large object heap.
+ * If we want 4-bytes alignment, we need to put vector and small bitmap
+ * inside complex.
+ */
+enum {
+	/*
+	 * We don't use 0 so that 0 isn't a valid GC descriptor.  No
+	 * deep reason for this other than to be able to identify a
+	 * non-inited descriptor for debugging.
+	 *
+	 * If an object contains no references, its GC descriptor is
+	 * always DESC_TYPE_RUN_LENGTH, without a size, no exceptions.
+	 * This is so that we can quickly check for that in
+	 * copy_object_no_checks(), without having to fetch the
+	 * object's class.
+	 */
+	DESC_TYPE_RUN_LENGTH = 1, /* 15 bits aligned byte size | 1-3 (offset, numptr) bytes tuples */
+	DESC_TYPE_SMALL_BITMAP, /* 15 bits aligned byte size | 16-48 bit bitmap */
+	DESC_TYPE_COMPLEX,      /* index for bitmap into complex_descriptors */
+	DESC_TYPE_VECTOR,       /* 10 bits element size | 1 bit array | 2 bits desc | element desc */
+	DESC_TYPE_ARRAY,        /* 10 bits element size | 1 bit array | 2 bits desc | element desc */
+	DESC_TYPE_LARGE_BITMAP, /* | 29-61 bitmap bits */
+	DESC_TYPE_COMPLEX_ARR,  /* index for bitmap into complex_descriptors */
+	/* subtypes for arrays and vectors */
+	DESC_TYPE_V_PTRFREE = 0,/* there are no refs: keep first so it has a zero value  */
+	DESC_TYPE_V_REFS,       /* all the array elements are refs */
+	DESC_TYPE_V_RUN_LEN,    /* elements are run-length encoded as DESC_TYPE_RUN_LENGTH */
+	DESC_TYPE_V_BITMAP      /* elements are as the bitmap in DESC_TYPE_SMALL_BITMAP */
+};
+
+#define SGEN_VTABLE_HAS_REFERENCES(vt)	(((MonoVTable*)(vt))->gc_descr != (void*)DESC_TYPE_RUN_LENGTH)
+
+/* helper macros to scan and traverse objects, macros because we resue them in many functions */
+#define OBJ_RUN_LEN_SIZE(size,desc,obj) do { \
+		(size) = ((desc) & 0xfff8) >> 1;	\
+    } while (0)
+
+#define OBJ_BITMAP_SIZE(size,desc,obj) do { \
+		(size) = ((desc) & 0xfff8) >> 1;	\
+    } while (0)
+
+//#define PREFETCH(addr) __asm__ __volatile__ ("     prefetchnta     %0": : "m"(*(char *)(addr)))
+#define PREFETCH(addr)
+
+/* code using these macros must define a HANDLE_PTR(ptr) macro that does the work */
+#define OBJ_RUN_LEN_FOREACH_PTR(desc,obj)	do {	\
+		if ((desc) & 0xffff0000) {	\
+			/* there are pointers */	\
+			void **_objptr_end;	\
+			void **_objptr = (void**)(obj);	\
+			_objptr += ((desc) >> 16) & 0xff;	\
+			_objptr_end = _objptr + (((desc) >> 24) & 0xff);	\
+			while (_objptr < _objptr_end) {	\
+				HANDLE_PTR (_objptr, (obj));	\
+				_objptr++;	\
+			}	\
+		}	\
+	} while (0)
+
+/* a bitmap desc means that there are pointer references or we'd have
+ * choosen run-length, instead: add an assert to check.
+ */
+#define OBJ_BITMAP_FOREACH_PTR(desc,obj)	do {	\
+		/* there are pointers */	\
+		void **_objptr = (void**)(obj);	\
+		gsize _bmap = (desc) >> 16;	\
+		_objptr += OBJECT_HEADER_WORDS;	\
+		while (_bmap) {	\
+			if ((_bmap & 1)) {	\
+				HANDLE_PTR (_objptr, (obj));	\
+			}	\
+			_bmap >>= 1;	\
+			++_objptr;	\
+		}	\
+	} while (0)
+
+#define OBJ_LARGE_BITMAP_FOREACH_PTR(vt,obj)	do {	\
+		/* there are pointers */	\
+		void **_objptr = (void**)(obj);	\
+		gsize _bmap = (vt)->desc >> LOW_TYPE_BITS;	\
+		_objptr += OBJECT_HEADER_WORDS;	\
+		while (_bmap) {	\
+			if ((_bmap & 1)) {	\
+				HANDLE_PTR (_objptr, (obj));	\
+			}	\
+			_bmap >>= 1;	\
+			++_objptr;	\
+		}	\
+	} while (0)
+
+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)
+
+#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;
+struct _SgenGrayQueue {
+	GrayQueueSection *first;
+	GrayQueueSection *free_list;
+	int balance;
+};
+
+#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;
@@ -177,6 +564,12 @@ 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,
@@ -215,6 +608,10 @@ 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;
 
@@ -233,5 +630,78 @@ void mono_sgen_internal_scan_objects (SgenInternalAllocator *alc, IterateObjectC
 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_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);
+};
+
+void mono_sgen_marksweep_init (SgenMajorCollector *collector, int nursery_bits, char *nursery_start, char *nursery_end) MONO_INTERNAL;
+void mono_sgen_copying_init (SgenMajorCollector *collector, int the_nursery_bits, char *the_nursery_start, char *the_nursery_end) 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__ */

+ 7 - 44
mono/metadata/sgen-gray.c

@@ -21,26 +21,8 @@
  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
-#define GRAY_QUEUE_SECTION_SIZE	(128 - 3)
 #define GRAY_QUEUE_LENGTH_LIMIT	64
 
-/*
- * 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 [GRAY_QUEUE_SECTION_SIZE];
-};
-
-struct _GrayQueue {
-	GrayQueueSection *first;
-	GrayQueueSection *free_list;
-	int balance;
-};
-
 static GrayQueue gray_queue;
 
 static void
@@ -79,23 +61,23 @@ gray_object_queue_is_empty (GrayQueue *queue)
 /*
  * The following two functions are called in the inner loops of the
  * collector, so they need to be as fast as possible.  We have macros
- * for them below.
+ * for them in sgen-gc.h.
  */
 
-static inline void
-gray_object_enqueue (GrayQueue *queue, char *obj)
+void
+mono_sgen_gray_object_enqueue (GrayQueue *queue, char *obj)
 {
 	DEBUG (9, g_assert (obj));
-	if (G_UNLIKELY (!queue->first || queue->first->end == GRAY_QUEUE_SECTION_SIZE))
+	if (G_UNLIKELY (!queue->first || queue->first->end == SGEN_GRAY_QUEUE_SECTION_SIZE))
 		gray_object_alloc_queue_section (queue);
-	DEBUG (9, g_assert (queue->first && queue->first->end < GRAY_QUEUE_SECTION_SIZE));
+	DEBUG (9, g_assert (queue->first && queue->first->end < SGEN_GRAY_QUEUE_SECTION_SIZE));
 	queue->first->objects [queue->first->end++] = obj;
 
 	DEBUG (9, ++queue->balance);
 }
 
-static inline char*
-gray_object_dequeue (GrayQueue *queue)
+char*
+mono_sgen_gray_object_dequeue (GrayQueue *queue)
 {
 	char *obj;
 
@@ -118,25 +100,6 @@ gray_object_dequeue (GrayQueue *queue)
 	return obj;
 }
 
-#if 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 == GRAY_QUEUE_SECTION_SIZE)) \
-			gray_object_alloc_queue_section ((queue));	\
-		(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) = gray_object_dequeue ((queue));		\
-		else							\
-			(o) = (queue)->first->objects [--(queue)->first->end]; \
-	} while (0)
-#endif
-
 static void
 gray_object_queue_init (GrayQueue *queue)
 {

+ 1 - 0
mono/metadata/sgen-internal.c

@@ -47,6 +47,7 @@
 
 #ifdef HAVE_SGEN_GC
 
+#include "utils/mono-counters.h"
 #include "metadata/sgen-gc.h"
 
 /* Pinned objects are allocated in the LOS space if bigger than half a page

+ 142 - 0
mono/metadata/sgen-major-copy-object.h

@@ -0,0 +1,142 @@
+extern long long stat_copy_object_called_nursery;
+extern long long stat_objects_copied_nursery;
+
+extern long long stat_nursery_copy_object_failed_from_space;
+extern long long stat_nursery_copy_object_failed_forwarded;
+extern long long stat_nursery_copy_object_failed_pinned;
+
+/*
+ * This function can be used even if the vtable of obj is not valid
+ * anymore, which is the case in the parallel collector.
+ */
+static void
+par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword objsize, SgenGrayQueue *queue)
+{
+	static const void *copy_labels [] = { &&LAB_0, &&LAB_1, &&LAB_2, &&LAB_3, &&LAB_4, &&LAB_5, &&LAB_6, &&LAB_7, &&LAB_8 };
+
+	DEBUG (9, g_assert (vt->klass->inited));
+	DEBUG (9, fprintf (gc_debug_file, " (to %p, %s size: %lu)\n", destination, ((MonoObject*)obj)->vtable->klass->name, (unsigned long)objsize));
+	binary_protocol_copy (obj, destination, vt, objsize);
+
+	*(MonoVTable**)destination = vt;
+	if (objsize <= sizeof (gpointer) * 8) {
+		mword *dest = (mword*)destination;
+		goto *copy_labels [objsize / sizeof (gpointer)];
+	LAB_8:
+		(dest) [7] = ((mword*)obj) [7];
+	LAB_7:
+		(dest) [6] = ((mword*)obj) [6];
+	LAB_6:
+		(dest) [5] = ((mword*)obj) [5];
+	LAB_5:
+		(dest) [4] = ((mword*)obj) [4];
+	LAB_4:
+		(dest) [3] = ((mword*)obj) [3];
+	LAB_3:
+		(dest) [2] = ((mword*)obj) [2];
+	LAB_2:
+		(dest) [1] = ((mword*)obj) [1];
+	LAB_1:
+		;
+	LAB_0:
+		;
+	} else {
+		memcpy (destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword));
+	}
+	/* adjust array->bounds */
+	DEBUG (9, g_assert (vt->gc_descr));
+	if (G_UNLIKELY (vt->rank && ((MonoArray*)obj)->bounds)) {
+		MonoArray *array = (MonoArray*)destination;
+		array->bounds = (MonoArrayBounds*)((char*)destination + ((char*)((MonoArray*)obj)->bounds - (char*)obj));
+		DEBUG (9, fprintf (gc_debug_file, "Array instance %p: size: %lu, rank: %d, length: %lu\n", array, (unsigned long)objsize, vt->rank, (unsigned long)mono_array_length (array)));
+	}
+	if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_GC_MOVES))
+		mono_sgen_register_moved_object (obj, destination);
+	obj = destination;
+	if (queue) {
+		DEBUG (9, fprintf (gc_debug_file, "Enqueuing gray object %p (%s)\n", obj, safe_name (obj)));
+		GRAY_OBJECT_ENQUEUE (queue, obj);
+	}
+}
+
+static void*
+copy_object_no_checks (void *obj, SgenGrayQueue *queue)
+{
+	MonoVTable *vt = ((MonoObject*)obj)->vtable;
+	gboolean has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
+	mword objsize = SGEN_ALIGN_UP (mono_sgen_par_object_get_size (vt, (MonoObject*)obj));
+	char *destination = major_alloc_object (objsize, has_references);
+
+	par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL);
+
+	/* set the forwarding pointer */
+	SGEN_FORWARD_OBJECT (obj, destination);
+
+	return destination;
+}
+
+/*
+ * This is how the copying happens from the nursery to the old generation.
+ * We assume that at this time all the pinned objects have been identified and
+ * marked as such.
+ * We run scan_object() for each pinned object so that each referenced
+ * objects if possible are copied. The new gray objects created can have
+ * scan_object() run on them right away, too.
+ * Then we run copy_object() for the precisely tracked roots. At this point
+ * all the roots are either gray or black. We run scan_object() on the gray
+ * objects until no more gray objects are created.
+ * At the end of the process we walk again the pinned list and we unmark
+ * the pinned flag. As we go we also create the list of free space for use
+ * in the next allocation runs.
+ *
+ * We need to remember objects from the old generation that point to the new one
+ * (or just addresses?).
+ *
+ * copy_object could be made into a macro once debugged (use inline for now).
+ */
+
+static void
+copy_object (void **obj_slot, SgenGrayQueue *queue)
+{
+	char *forwarded;
+	char *obj = *obj_slot;
+
+	DEBUG (9, g_assert (current_collection_generation == GENERATION_NURSERY));
+
+	HEAVY_STAT (++stat_copy_object_called_nursery);
+
+	if (!ptr_in_nursery (obj)) {
+		HEAVY_STAT (++stat_nursery_copy_object_failed_from_space);
+		return;
+	}
+
+	DEBUG (9, fprintf (gc_debug_file, "Precise copy of %p from %p", obj, obj_slot));
+
+	/*
+	 * Before we can copy the object we must make sure that we are
+	 * allowed to, i.e. that the object not pinned or not already
+	 * forwarded.
+	 */
+
+	if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) {
+		DEBUG (9, g_assert (((MonoVTable*)LOAD_VTABLE(obj))->gc_descr));
+		DEBUG (9, fprintf (gc_debug_file, " (already forwarded to %p)\n", forwarded));
+		HEAVY_STAT (++stat_nursery_copy_object_failed_forwarded);
+		*obj_slot = forwarded;
+		return;
+	}
+	if (SGEN_OBJECT_IS_PINNED (obj)) {
+		DEBUG (9, g_assert (((MonoVTable*)LOAD_VTABLE(obj))->gc_descr));
+		DEBUG (9, fprintf (gc_debug_file, " (pinned, no change)\n"));
+		HEAVY_STAT (++stat_nursery_copy_object_failed_pinned);
+		return;
+	}
+
+	HEAVY_STAT (++stat_objects_copied_nursery);
+
+	*obj_slot = copy_object_no_checks (obj, queue);
+}
+
+#define FILL_COLLECTOR_COPY_OBJECT(collector)	do {			\
+		(collector)->copy_object = copy_object;			\
+	} while (0)

+ 135 - 74
mono/metadata/sgen-major-copying.c

@@ -45,9 +45,16 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#ifdef SGEN_PARALLEL_MARK
-#error Parallel mark not supported in copying major collector
-#endif
+#ifdef HAVE_SGEN_GC
+
+#include "utils/mono-counters.h"
+#include "metadata/object-internals.h"
+#include "metadata/profiler-private.h"
+
+#include "metadata/sgen-gc.h"
+#include "metadata/sgen-protocol.h"
+
+#define DEBUG(l,x)
 
 #define MAJOR_SECTION_SIZE		SGEN_PINNED_CHUNK_SIZE
 #define BLOCK_FOR_OBJECT(o)		SGEN_PINNED_CHUNK_FOR_PTR ((o))
@@ -68,6 +75,13 @@ static char *to_space_bumper = NULL;
 static char *to_space_top = NULL;
 static GCMemSection *to_space_section = NULL;
 
+/* we get this at init */
+static int nursery_bits;
+static char *nursery_start;
+static char *nursery_end;
+
+#define ptr_in_nursery(p)	(SGEN_PTR_IN_NURSERY ((p), nursery_bits, nursery_start, nursery_end))
+
 #ifdef HEAVY_STATISTICS
 static long stat_major_copy_object_failed_forwarded = 0;
 static long stat_major_copy_object_failed_pinned = 0;
@@ -97,13 +111,13 @@ alloc_major_section (void)
 	int scan_starts;
 
 	section = mono_sgen_alloc_os_memory_aligned (MAJOR_SECTION_SIZE, MAJOR_SECTION_SIZE, TRUE);
-	section->next_data = section->data = (char*)section + SIZEOF_GC_MEM_SECTION;
+	section->next_data = section->data = (char*)section + SGEN_SIZEOF_GC_MEM_SECTION;
 	g_assert (!((mword)section->data & 7));
-	section->size = MAJOR_SECTION_SIZE - SIZEOF_GC_MEM_SECTION;
+	section->size = MAJOR_SECTION_SIZE - SGEN_SIZEOF_GC_MEM_SECTION;
 	section->end_data = section->data + section->size;
 	mono_sgen_update_heap_boundaries ((mword)section->data, (mword)section->end_data);
 	DEBUG (3, fprintf (gc_debug_file, "New major heap section: (%p-%p), total: %zd\n", section->data, section->end_data, total_alloc));
-	scan_starts = (section->size + SCAN_START_SIZE - 1) / SCAN_START_SIZE;
+	scan_starts = (section->size + SGEN_SCAN_START_SIZE - 1) / SGEN_SCAN_START_SIZE;
 	section->scan_starts = mono_sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS);
 	section->num_scan_start = scan_starts;
 	section->block.role = MEMORY_ROLE_GEN1;
@@ -123,7 +137,7 @@ free_major_section (GCMemSection *section)
 {
 	DEBUG (3, fprintf (gc_debug_file, "Freed major section %p (%p-%p)\n", section, section->data, section->end_data));
 	mono_sgen_free_internal_dynamic (section->scan_starts,
-			(section->size + SCAN_START_SIZE - 1) / SCAN_START_SIZE * sizeof (char*), INTERNAL_MEM_SCAN_STARTS);
+			(section->size + SGEN_SCAN_START_SIZE - 1) / SGEN_SCAN_START_SIZE * sizeof (char*), INTERNAL_MEM_SCAN_STARTS);
 	mono_sgen_free_os_memory (section, MAJOR_SECTION_SIZE);
 
 	--num_major_sections;
@@ -158,18 +172,21 @@ to_space_expand (void)
 	new_to_space_section ();
 }
 
-#define MAJOR_GET_COPY_OBJECT_SPACE(dest, size, refs) do {		\
-		(dest) = to_space_bumper;				\
-		/* Make sure we have enough space available */		\
-		if ((dest) + (size) > to_space_top) {			\
-			to_space_expand ();				\
-			(dest) = to_space_bumper;			\
-			DEBUG (8, g_assert ((dest) + (objsize) <= to_space_top)); \
-		}							\
-		to_space_bumper += objsize;				\
-		DEBUG (8, g_assert (to_space_bumper <= to_space_top));	\
-		to_space_section->scan_starts [((dest) - (char*)to_space_section->data)/SCAN_START_SIZE] = (dest); \
-	} while (0)
+static void*
+major_alloc_object (int size, gboolean has_references)
+{
+	char *dest = to_space_bumper;
+	/* Make sure we have enough space available */
+	if (dest + size > to_space_top) {
+		to_space_expand ();
+		(dest) = to_space_bumper;
+		DEBUG (8, g_assert (dest + size <= to_space_top));
+	}
+	to_space_bumper += size;
+	DEBUG (8, g_assert (to_space_bumper <= to_space_top));
+	to_space_section->scan_starts [(dest - (char*)to_space_section->data)/SGEN_SCAN_START_SIZE] = dest;
+	return dest;
+}
 
 static void
 unset_to_space (void)
@@ -193,10 +210,10 @@ major_is_object_live (char *obj)
 	if (ptr_in_nursery (obj))
 		return FALSE;
 
-	objsize = SGEN_ALIGN_UP (safe_object_get_size ((MonoObject*)obj));
+	objsize = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)obj));
 
 	/* LOS */
-	if (objsize > MAX_SMALL_OBJ_SIZE)
+	if (objsize > SGEN_MAX_SMALL_OBJ_SIZE)
 		return FALSE;
 
 	/* pinned chunk */
@@ -222,7 +239,7 @@ major_alloc_degraded (MonoVTable *vtable, size_t size)
 {
 	GCMemSection *section;
 	void **p = NULL;
-	g_assert (size <= MAX_SMALL_OBJ_SIZE);
+	g_assert (size <= SGEN_MAX_SMALL_OBJ_SIZE);
 	HEAVY_STAT (++stat_objects_alloced_degraded);
 	HEAVY_STAT (stat_bytes_alloced_degraded += size);
 	for (section = section_list; section; section = section->block.next) {
@@ -236,17 +253,18 @@ major_alloc_degraded (MonoVTable *vtable, size_t size)
 		section->is_to_space = FALSE;
 		/* FIXME: handle OOM */
 		p = (void**)section->next_data;
-		++minor_collection_sections_alloced;
+		mono_sgen_register_major_sections_alloced (1);
 	}
 	section->next_data += size;
-	degraded_mode += size;
 	DEBUG (3, fprintf (gc_debug_file, "Allocated (degraded) object %p, vtable: %p (%s), size: %zd in section %p\n", p, vtable, vtable->klass->name, size, section));
 	*p = vtable;
 	return p;
 }
 
+#include "sgen-major-copy-object.h"
+
 static void
-major_copy_or_mark_object (void **obj_slot, GrayQueue *queue)
+major_copy_or_mark_object (void **obj_slot, SgenGrayQueue *queue)
 {
 	char *forwarded;
 	char *obj = *obj_slot;
@@ -283,15 +301,15 @@ major_copy_or_mark_object (void **obj_slot, GrayQueue *queue)
 	 * get to-space objects.
 	 */
 
-	if ((forwarded = object_is_forwarded (obj))) {
-		DEBUG (9, g_assert (((MonoVTable*)LOAD_VTABLE(obj))->gc_descr));
+	if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) {
+		DEBUG (9, g_assert (((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr));
 		DEBUG (9, fprintf (gc_debug_file, " (already forwarded to %p)\n", forwarded));
 		HEAVY_STAT (++stat_major_copy_object_failed_forwarded);
 		*obj_slot = forwarded;
 		return;
 	}
-	if (object_is_pinned (obj)) {
-		DEBUG (9, g_assert (((MonoVTable*)LOAD_VTABLE(obj))->gc_descr));
+	if (SGEN_OBJECT_IS_PINNED (obj)) {
+		DEBUG (9, g_assert (((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr));
 		DEBUG (9, fprintf (gc_debug_file, " (pinned, no change)\n"));
 		HEAVY_STAT (++stat_major_copy_object_failed_pinned);
 		return;
@@ -305,10 +323,10 @@ major_copy_or_mark_object (void **obj_slot, GrayQueue *queue)
 	 * belongs to 2, 3, 4, or 5.
 	 *
 	 * LOS object (2) are simple, at least until we always follow
-	 * the rule: if objsize > MAX_SMALL_OBJ_SIZE, pin the object
-	 * and return it.  At the end of major collections, we walk
-	 * the los list and if the object is pinned, it is marked,
-	 * otherwise it can be freed.
+	 * the rule: if objsize > SGEN_MAX_SMALL_OBJ_SIZE, pin the
+	 * object and return it.  At the end of major collections, we
+	 * walk the los list and if the object is pinned, it is
+	 * marked, otherwise it can be freed.
 	 *
 	 * Pinned chunks (3) and major heap sections (4, 5) both
 	 * reside in blocks, which are always aligned, so once we've
@@ -316,14 +334,14 @@ major_copy_or_mark_object (void **obj_slot, GrayQueue *queue)
 	 * see whether it's a pinned chunk or a major heap section.
 	 */
 
-	objsize = SGEN_ALIGN_UP (safe_object_get_size ((MonoObject*)obj));
+	objsize = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)obj));
 
-	if (G_UNLIKELY (objsize > MAX_SMALL_OBJ_SIZE || obj_is_from_pinned_alloc (obj))) {
-		if (object_is_pinned (obj))
+	if (G_UNLIKELY (objsize > SGEN_MAX_SMALL_OBJ_SIZE || obj_is_from_pinned_alloc (obj))) {
+		if (SGEN_OBJECT_IS_PINNED (obj))
 			return;
 		DEBUG (9, fprintf (gc_debug_file, " (marked LOS/Pinned %p (%s), size: %zd)\n", obj, safe_name (obj), objsize));
-		binary_protocol_pin (obj, (gpointer)LOAD_VTABLE (obj), safe_object_get_size ((MonoObject*)obj));
-		pin_object (obj);
+		binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), mono_sgen_safe_object_get_size ((MonoObject*)obj));
+		SGEN_PIN_OBJECT (obj);
 		GRAY_OBJECT_ENQUEUE (queue, obj);
 		HEAVY_STAT (++stat_major_copy_object_failed_large_pinned);
 		return;
@@ -335,7 +353,7 @@ major_copy_or_mark_object (void **obj_slot, GrayQueue *queue)
 	 * not (4).
 	 */
 	if (MAJOR_OBJ_IS_IN_TO_SPACE (obj)) {
-		DEBUG (9, g_assert (objsize <= MAX_SMALL_OBJ_SIZE));
+		DEBUG (9, g_assert (objsize <= SGEN_MAX_SMALL_OBJ_SIZE));
 		DEBUG (9, fprintf (gc_debug_file, " (already copied)\n"));
 		HEAVY_STAT (++stat_major_copy_object_failed_to_space);
 		return;
@@ -347,6 +365,8 @@ major_copy_or_mark_object (void **obj_slot, GrayQueue *queue)
 	*obj_slot = copy_object_no_checks (obj, queue);
 }
 
+#include "sgen-major-scan-object.h"
+
 /* FIXME: later reduce code duplication here with build_nursery_fragments().
  * We don't keep track of section fragments for non-nursery sections yet, so
  * just memset to 0.
@@ -362,22 +382,22 @@ build_section_fragments (GCMemSection *section)
 	memset (section->scan_starts, 0, section->num_scan_start * sizeof (gpointer));
 	frag_start = section->data;
 	section->next_data = section->data;
-	for (i = section->pin_queue_start; i < section->pin_queue_end; ++i) {
-		frag_end = pin_queue [i];
+	for (i = 0; i < section->pin_queue_num_entries; ++i) {
+		frag_end = section->pin_queue_start [i];
 		/* remove the pin bit from pinned objects */
-		unpin_object (frag_end);
+		SGEN_UNPIN_OBJECT (frag_end);
 		if (frag_end >= section->data + section->size) {
 			frag_end = section->data + section->size;
 		} else {
-			section->scan_starts [((char*)frag_end - (char*)section->data)/SCAN_START_SIZE] = frag_end;
+			section->scan_starts [((char*)frag_end - (char*)section->data)/SGEN_SCAN_START_SIZE] = frag_end;
 		}
 		frag_size = frag_end - frag_start;
 		if (frag_size) {
 			binary_protocol_empty (frag_start, frag_size);
 			memset (frag_start, 0, frag_size);
 		}
-		frag_size = SGEN_ALIGN_UP (safe_object_get_size ((MonoObject*)pin_queue [i]));
-		frag_start = (char*)pin_queue [i] + frag_size;
+		frag_size = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)section->pin_queue_start [i]));
+		frag_start = (char*)section->pin_queue_start [i] + frag_size;
 		section->next_data = MAX (section->next_data, frag_start);
 	}
 	frag_end = section->end_data;
@@ -391,8 +411,8 @@ build_section_fragments (GCMemSection *section)
 static void
 sweep_pinned_objects_callback (char *ptr, size_t size, void *data)
 {
-	if (object_is_pinned (ptr)) {
-		unpin_object (ptr);
+	if (SGEN_OBJECT_IS_PINNED (ptr)) {
+		SGEN_UNPIN_OBJECT (ptr);
 		DEBUG (6, fprintf (gc_debug_file, "Unmarked pinned object %p (%s)\n", ptr, safe_name (ptr)));
 	} else {
 		DEBUG (6, fprintf (gc_debug_file, "Freeing unmarked pinned object %p (%s)\n", ptr, safe_name (ptr)));
@@ -412,7 +432,7 @@ major_iterate_objects (gboolean non_pinned, gboolean pinned, IterateObjectCallba
 	if (non_pinned) {
 		GCMemSection *section;
 		for (section = section_list; section; section = section->block.next)
-			scan_area_with_callback (section->data, section->end_data, callback, data);
+			mono_sgen_scan_area_with_callback (section->data, section->end_data, callback, data);
 	}
 	if (pinned)
 		mono_sgen_internal_scan_objects (&pinned_allocator, callback, data);
@@ -425,33 +445,33 @@ major_free_non_pinned_object (char *obj, size_t size)
 }
 
 static void
-pin_pinned_object_callback (void *addr, size_t slot_size, GrayQueue *queue)
+pin_pinned_object_callback (void *addr, size_t slot_size, SgenGrayQueue *queue)
 {
-	binary_protocol_pin (addr, (gpointer)LOAD_VTABLE (addr), safe_object_get_size ((MonoObject*)addr));
-	if (heap_dump_file && !object_is_pinned (addr))
-		pin_stats_register_object ((char*) addr, safe_object_get_size ((MonoObject*) addr));
-	pin_object (addr);
+	binary_protocol_pin (addr, (gpointer)SGEN_LOAD_VTABLE (addr), mono_sgen_safe_object_get_size ((MonoObject*)addr));
+	if (!SGEN_OBJECT_IS_PINNED (addr))
+		mono_sgen_pin_stats_register_object ((char*) addr, mono_sgen_safe_object_get_size ((MonoObject*) addr));
+	SGEN_PIN_OBJECT (addr);
 	GRAY_OBJECT_ENQUEUE (queue, addr);
 	DEBUG (6, fprintf (gc_debug_file, "Marked pinned object %p (%s) from roots\n", addr, safe_name (addr)));
 }
 
 static void
-major_find_pin_queue_start_ends (GrayQueue *queue)
+major_find_pin_queue_start_ends (SgenGrayQueue *queue)
 {
 	GCMemSection *section;
 
 	for (section = section_list; section; section = section->block.next)
-		find_section_pin_queue_start_end (section);
+		mono_sgen_find_section_pin_queue_start_end (section);
 	mono_sgen_internal_scan_pinned_objects (&pinned_allocator, (IterateObjectCallbackFunc)pin_pinned_object_callback, queue);
 }
 
 static void
-major_pin_objects (GrayQueue *queue)
+major_pin_objects (SgenGrayQueue *queue)
 {
 	GCMemSection *section;
 
 	for (section = section_list; section; section = section->block.next)
-		pin_objects_in_section (section, queue);
+		mono_sgen_pin_objects_in_section (section, queue);
 }
 
 static void
@@ -482,8 +502,9 @@ major_sweep (void)
 			continue;
 		}
 		/* no pinning object, so the section is free */
-		if (section->pin_queue_start == section->pin_queue_end) {
+		if (!section->pin_queue_num_entries) {
 			GCMemSection *to_free;
+			g_assert (!section->pin_queue_start);
 			if (prev_section)
 				prev_section->block.next = section->block.next;
 			else
@@ -493,7 +514,7 @@ major_sweep (void)
 			free_major_section (to_free);
 			continue;
 		} else {
-			DEBUG (6, fprintf (gc_debug_file, "Section %p has still pinned objects (%d)\n", section, section->pin_queue_end - section->pin_queue_start));
+			DEBUG (6, fprintf (gc_debug_file, "Section %p has still pinned objects (%d)\n", section, section->pin_queue_num_entries));
 			build_section_fragments (section);
 		}
 		prev_section = section;
@@ -506,15 +527,15 @@ major_check_scan_starts (void)
 {
 	GCMemSection *section;
 	for (section = section_list; section; section = section->block.next)
-		check_section_scan_starts (section);
+		mono_sgen_check_section_scan_starts (section);
 }
 
 static void
-major_dump_heap (void)
+major_dump_heap (FILE *heap_dump_file)
 {
 	GCMemSection *section;
 	for (section = section_list; section; section = section->block.next)
-		dump_section (section, "old");
+		mono_sgen_dump_section (section, "old");
 	/* FIXME: dump pinned sections, too */
 }
 
@@ -530,17 +551,6 @@ major_get_used_size (void)
 	return tot;
 }
 
-static void
-major_init (void)
-{
-#ifdef HEAVY_STATISTICS
-	mono_counters_register ("# major copy_object() failed forwarded", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_forwarded);
-	mono_counters_register ("# major copy_object() failed pinned", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_pinned);
-	mono_counters_register ("# major copy_object() failed large or pinned chunk", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_large_pinned);
-	mono_counters_register ("# major copy_object() failed to space", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_to_space);
-#endif
-}
-
 /* only valid during minor collections */
 static int old_num_major_sections;
 
@@ -573,7 +583,7 @@ major_finish_nursery_collection (void)
 		section->is_to_space = FALSE;
 
 	sections_alloced = num_major_sections - old_num_major_sections;
-	minor_collection_sections_alloced += sections_alloced;
+	mono_sgen_register_major_sections_alloced (sections_alloced);
 }
 
 static void
@@ -598,3 +608,54 @@ major_report_pinned_memory_usage (void)
 {
 	mono_sgen_report_internal_mem_usage_full (&pinned_allocator);
 }
+
+static int
+get_num_major_sections (void)
+{
+	return num_major_sections;
+}
+
+void
+mono_sgen_copying_init (SgenMajorCollector *collector, int the_nursery_bits, char *the_nursery_start, char *the_nursery_end)
+{
+	nursery_bits = the_nursery_bits;
+	nursery_start = the_nursery_start;
+	nursery_end = the_nursery_end;
+
+#ifdef HEAVY_STATISTICS
+	mono_counters_register ("# major copy_object() failed forwarded", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_forwarded);
+	mono_counters_register ("# major copy_object() failed pinned", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_pinned);
+	mono_counters_register ("# major copy_object() failed large or pinned chunk", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_large_pinned);
+	mono_counters_register ("# major copy_object() failed to space", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_to_space);
+#endif
+
+	collector->section_size = MAJOR_SECTION_SIZE;
+
+	collector->is_object_live = major_is_object_live;
+	collector->alloc_small_pinned_obj = major_alloc_small_pinned_obj;
+	collector->alloc_degraded = major_alloc_degraded;
+	collector->copy_or_mark_object = major_copy_or_mark_object;
+	collector->alloc_object = major_alloc_object;
+	collector->free_pinned_object = free_pinned_object;
+	collector->iterate_objects = major_iterate_objects;
+	collector->free_non_pinned_object = major_free_non_pinned_object;
+	collector->find_pin_queue_start_ends = major_find_pin_queue_start_ends;
+	collector->pin_objects = major_pin_objects;
+	collector->init_to_space = major_init_to_space;
+	collector->sweep = major_sweep;
+	collector->check_scan_starts = major_check_scan_starts;
+	collector->dump_heap = major_dump_heap;
+	collector->get_used_size = major_get_used_size;
+	collector->start_nursery_collection = major_start_nursery_collection;
+	collector->finish_nursery_collection = major_finish_nursery_collection;
+	collector->finish_major_collection = major_finish_major_collection;
+	collector->ptr_is_in_non_pinned_space = major_ptr_is_in_non_pinned_space;
+	collector->obj_is_from_pinned_alloc = obj_is_from_pinned_alloc;
+	collector->report_pinned_memory_usage = major_report_pinned_memory_usage;
+	collector->get_num_major_sections = get_num_major_sections;
+
+	FILL_COLLECTOR_COPY_OBJECT (collector);
+	FILL_COLLECTOR_SCAN_OBJECT (collector);
+}
+
+#endif

+ 93 - 0
mono/metadata/sgen-major-scan-object.h

@@ -0,0 +1,93 @@
+extern long long stat_scan_object_called_nursery;
+extern long long stat_scan_object_called_major;
+
+#undef HANDLE_PTR
+#define HANDLE_PTR(ptr,obj)	do {	\
+		void *__old = *(ptr);	\
+		void *__copy;		\
+		if (__old) {	\
+			copy_object ((ptr), queue);	\
+			__copy = *(ptr);	\
+			DEBUG (9, if (__old != __copy) fprintf (gc_debug_file, "Overwrote field at %p with %p (was: %p)\n", (ptr), *(ptr), __old));	\
+			if (G_UNLIKELY (ptr_in_nursery (__copy) && !ptr_in_nursery ((ptr)))) \
+				mono_sgen_add_to_global_remset ((ptr));	\
+		}	\
+	} while (0)
+
+/*
+ * Scan the object pointed to by @start for references to
+ * other objects between @from_start and @from_end and copy
+ * them to the gray_objects area.
+ */
+static void
+minor_scan_object (char *start, SgenGrayQueue *queue)
+{
+#include "sgen-scan-object.h"
+
+	HEAVY_STAT (++stat_scan_object_called_nursery);
+}
+
+/*
+ * scan_vtype:
+ *
+ * Scan the valuetype pointed to by START, described by DESC for references to
+ * other objects between @from_start and @from_end and copy them to the gray_objects area.
+ * Returns a pointer to the end of the object.
+ */
+static char*
+minor_scan_vtype (char *start, mword desc, char* from_start, char* from_end, SgenGrayQueue *queue)
+{
+	size_t skip_size;
+
+	/* The descriptors include info about the MonoObject header as well */
+	start -= sizeof (MonoObject);
+
+	switch (desc & 0x7) {
+	case DESC_TYPE_RUN_LENGTH:
+		OBJ_RUN_LEN_FOREACH_PTR (desc,start);
+		OBJ_RUN_LEN_SIZE (skip_size, desc, start);
+		g_assert (skip_size);
+		return start + skip_size;
+	case DESC_TYPE_SMALL_BITMAP:
+		OBJ_BITMAP_FOREACH_PTR (desc,start);
+		OBJ_BITMAP_SIZE (skip_size, desc, start);
+		return start + skip_size;
+	case DESC_TYPE_LARGE_BITMAP:
+	case DESC_TYPE_COMPLEX:
+		// FIXME:
+		g_assert_not_reached ();
+		break;
+	default:
+		// The other descriptors can't happen with vtypes
+		g_assert_not_reached ();
+		break;
+	}
+	return NULL;
+}
+
+#undef HANDLE_PTR
+#define HANDLE_PTR(ptr,obj)	do {					\
+		void *__old = *(ptr);					\
+		void *__copy;						\
+		if (__old) {						\
+			major_copy_or_mark_object ((ptr), queue);	\
+			__copy = *(ptr);				\
+			DEBUG (9, if (__old != __copy) mono_sgen_debug_printf (9, "Overwrote field at %p with %p (was: %p)\n", (ptr), *(ptr), __old)); \
+			if (G_UNLIKELY (ptr_in_nursery (__copy) && !ptr_in_nursery ((ptr)))) \
+				mono_sgen_add_to_global_remset ((ptr));	\
+		}							\
+	} while (0)
+
+static void
+major_scan_object (char *start, SgenGrayQueue *queue)
+{
+#include "sgen-scan-object.h"
+
+	HEAVY_STAT (++stat_scan_object_called_major);
+}
+
+#define FILL_COLLECTOR_SCAN_OBJECT(collector)	do {			\
+		(collector)->major_scan_object = major_scan_object;	\
+		(collector)->minor_scan_object = minor_scan_object;	\
+		(collector)->minor_scan_vtype = minor_scan_vtype;	\
+	} while (0)

+ 174 - 89
mono/metadata/sgen-marksweep.c

@@ -1,5 +1,44 @@
+/*
+ * sgen-marksweep.c: Simple generational GC.
+ *
+ * Author:
+ * 	Mark Probst <[email protected]>
+ *
+ * Copyright 2009-2010 Novell, Inc.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_SGEN_GC
+
 #include <math.h>
 
+#include "utils/mono-counters.h"
+#include "metadata/object-internals.h"
+#include "metadata/profiler-private.h"
+
+#include "metadata/sgen-gc.h"
+#include "metadata/sgen-protocol.h"
+
+#define DEBUG(l,x)
+
 #define MS_BLOCK_SIZE	(16*1024)
 #define MAJOR_SECTION_SIZE	MS_BLOCK_SIZE
 
@@ -18,9 +57,9 @@
 
 #define MS_BLOCK_FREE	(MS_BLOCK_SIZE - MS_BLOCK_SKIP)
 
-#define MS_NUM_MARK_WORDS	((MS_BLOCK_SIZE / ALLOC_ALIGN + sizeof (mword) * 8 - 1) / (sizeof (mword) * 8))
+#define MS_NUM_MARK_WORDS	((MS_BLOCK_SIZE / SGEN_ALLOC_ALIGN + sizeof (mword) * 8 - 1) / (sizeof (mword) * 8))
 
-#if MAX_SMALL_OBJ_SIZE > MS_BLOCK_FREE / 2
+#if SGEN_MAX_SMALL_OBJ_SIZE > MS_BLOCK_FREE / 2
 #error MAX_SMALL_OBJ_SIZE must be at most (MS_BLOCK_SIZE - MS_BLOCK_SKIP) / 2
 #endif
 
@@ -33,8 +72,8 @@ struct _MSBlockInfo {
 	void **free_list;
 	MSBlockInfo *next_free;
 	MSBlockInfo *next;
-	int pin_queue_start;
-	int pin_queue_end;
+	void **pin_queue_start;
+	int pin_queue_num_entries;
 	mword mark_words [MS_NUM_MARK_WORDS];
 };
 
@@ -49,7 +88,7 @@ typedef struct {
 #define MS_BLOCK_OBJ_INDEX(o,b)	(((char*)(o) - ((b)->block + MS_BLOCK_SKIP)) / (b)->obj_size)
 
 #define MS_CALC_MARK_BIT(w,b,o,bl) 	do {				\
-		int i = ((char*)(o) - (bl)->block) >> ALLOC_ALIGN_BITS; \
+		int i = ((char*)(o) - (bl)->block) >> SGEN_ALLOC_ALIGN_BITS; \
 		if (sizeof (mword) == 4) {				\
 			(w) = i >> 5;					\
 			(b) = i & 31;					\
@@ -105,6 +144,13 @@ static LOCK_DECLARE (ms_block_list_mutex);
 #define UNLOCK_MS_BLOCK_LIST
 #endif
 
+/* we get this at init */
+static int nursery_bits;
+static char *nursery_start;
+static char *nursery_end;
+
+#define ptr_in_nursery(p)	(SGEN_PTR_IN_NURSERY ((p), nursery_bits, nursery_start, nursery_end))
+
 /* non-allocated block free-list */
 static void *empty_blocks = NULL;
 static int num_empty_blocks = 0;
@@ -121,7 +167,7 @@ static int
 ms_find_block_obj_size_index (int size)
 {
 	int i;
-	DEBUG (9, g_assert (size <= MAX_SMALL_OBJ_SIZE));
+	DEBUG (9, g_assert (size <= SGEN_MAX_SMALL_OBJ_SIZE));
 	for (i = 0; i < num_block_obj_sizes; ++i)
 		if (block_obj_sizes [i] >= size)
 			return i;
@@ -365,16 +411,11 @@ alloc_obj (int size, gboolean pinned, gboolean has_references)
 }
 
 static void*
-ms_alloc_obj (int size, gboolean has_references)
+major_alloc_object (int size, gboolean has_references)
 {
 	return alloc_obj (size, FALSE, has_references);
 }
 
-/* FIXME: inline fast path */
-#define MAJOR_GET_COPY_OBJECT_SPACE(dest, size, refs) do {	\
-		(dest) = ms_alloc_obj ((size), (refs));		\
-	} while (0)
-
 /*
  * We're not freeing the block if it's empty.  We leave that work for
  * the next major collection.
@@ -409,7 +450,7 @@ major_free_non_pinned_object (char *obj, size_t size)
 	free_object (obj, size, FALSE);
 }
 
-/* size is a multiple of ALLOC_ALIGN */
+/* size is a multiple of SGEN_ALLOC_ALIGN */
 static void*
 major_alloc_small_pinned_obj (size_t size, gboolean has_references)
 {
@@ -435,7 +476,7 @@ major_alloc_degraded (MonoVTable *vtable, size_t size)
 	HEAVY_STAT (++stat_objects_alloced_degraded);
 	HEAVY_STAT (stat_bytes_alloced_degraded += size);
 	g_assert (num_major_sections >= old_num_sections);
-	minor_collection_sections_alloced += num_major_sections - old_num_sections;
+	mono_sgen_register_major_sections_alloced (num_major_sections - old_num_sections);
 	return obj;
 }
 
@@ -456,10 +497,10 @@ major_is_object_live (char *obj)
 	if (ptr_in_nursery (obj))
 		return FALSE;
 
-	objsize = ALIGN_UP (safe_object_get_size ((MonoObject*)obj));
+	objsize = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)obj));
 
 	/* LOS */
-	if (objsize > MAX_SMALL_OBJ_SIZE)
+	if (objsize > SGEN_MAX_SMALL_OBJ_SIZE)
 		return FALSE;
 
 	/* now we know it's in a major block */
@@ -497,10 +538,13 @@ major_iterate_objects (gboolean non_pinned, gboolean pinned, IterateObjectCallba
 	}
 }
 
-#define major_check_scan_starts()
+static void
+major_check_scan_starts (void)
+{
+}
 
 static void
-major_dump_heap (void)
+major_dump_heap (FILE *heap_dump_file)
 {
 	MSBlockInfo *block;
 
@@ -517,7 +561,7 @@ major_dump_heap (void)
 					start = i;
 			} else {
 				if (start >= 0) {
-					dump_occupied (MS_BLOCK_OBJ (block, start), MS_BLOCK_OBJ (block, i), block->block);
+					mono_sgen_dump_occupied (MS_BLOCK_OBJ (block, start), MS_BLOCK_OBJ (block, i), block->block);
 					start = -1;
 				}
 			}
@@ -527,6 +571,8 @@ major_dump_heap (void)
 	}
 }
 
+#define LOAD_VTABLE	SGEN_LOAD_VTABLE
+
 #define MS_MARK_OBJECT_AND_ENQUEUE_CHECKED(obj,block,queue) do {	\
 		int __word, __bit;					\
 		MS_CALC_MARK_BIT (__word, __bit, (obj), (block));	\
@@ -534,7 +580,7 @@ major_dump_heap (void)
 			MS_SET_MARK_BIT ((block), __word, __bit);	\
 			if ((block)->has_references)			\
 				GRAY_OBJECT_ENQUEUE ((queue), (obj));	\
-			binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), safe_object_get_size ((MonoObject*)(obj))); \
+			binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), mono_sgen_safe_object_get_size ((MonoObject*)(obj))); \
 		}							\
 	} while (0)
 #define MS_MARK_OBJECT_AND_ENQUEUE(obj,block,queue) do {		\
@@ -546,16 +592,18 @@ major_dump_heap (void)
 		if (!__was_marked) {					\
 			if ((block)->has_references)			\
 				GRAY_OBJECT_ENQUEUE ((queue), (obj));	\
-			binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), safe_object_get_size ((MonoObject*)(obj))); \
+			binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), mono_sgen_safe_object_get_size ((MonoObject*)(obj))); \
 		}							\
 	} while (0)
 
+#include "sgen-major-copy-object.h"
+
 static void
-major_copy_or_mark_object (void **ptr, GrayQueue *queue)
+major_copy_or_mark_object (void **ptr, SgenGrayQueue *queue)
 {
 	void *obj = *ptr;
 	mword vtable_word = *(mword*)obj;
-	MonoVTable *vt = (MonoVTable*)(vtable_word & ~VTABLE_BITS_MASK);
+	MonoVTable *vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
 	mword objsize;
 	MSBlockInfo *block;
 
@@ -569,22 +617,22 @@ major_copy_or_mark_object (void **ptr, GrayQueue *queue)
 		gboolean has_references;
 		void *destination;
 
-		if (vtable_word & FORWARDED_BIT) {
+		if (vtable_word & SGEN_FORWARDED_BIT) {
 			*ptr = (void*)vt;
 			return;
 		}
 
-		if (vtable_word & PINNED_BIT)
+		if (vtable_word & SGEN_PINNED_BIT)
 			return;
 
 		HEAVY_STAT (++stat_objects_copied_major);
 
-		objsize = ALIGN_UP (par_object_get_size (vt, (MonoObject*)obj));
-		has_references = VTABLE_HAS_REFERENCES (vt);
+		objsize = SGEN_ALIGN_UP (mono_sgen_par_object_get_size (vt, (MonoObject*)obj));
+		has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
 
-		destination = ms_alloc_obj (objsize, has_references);
+		destination = major_alloc_object (objsize, has_references);
 
-		if (SGEN_CAS_PTR (obj, (void*)((mword)destination | FORWARDED_BIT), vt) == vt) {
+		if (SGEN_CAS_PTR (obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) {
 			gboolean was_marked;
 
 			par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL);
@@ -592,8 +640,8 @@ major_copy_or_mark_object (void **ptr, GrayQueue *queue)
 			*ptr = obj;
 
 			/*
-			 * FIXME: If we make ms_alloc_obj() give us
-			 * the block info, too, we won't have to
+			 * FIXME: If we make major_alloc_object() give
+			 * us the block info, too, we won't have to
 			 * re-fetch it here.
 			 */
 			block = MS_BLOCK_FOR_OBJ (obj);
@@ -609,26 +657,26 @@ major_copy_or_mark_object (void **ptr, GrayQueue *queue)
 			*(void**)destination = NULL;
 
 			vtable_word = *(mword*)obj;
-			g_assert (vtable_word & FORWARDED_BIT);
+			g_assert (vtable_word & SGEN_FORWARDED_BIT);
 
-			obj = (void*)(vtable_word & ~VTABLE_BITS_MASK);
+			obj = (void*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
 
 			*ptr = obj;
 		}
 		return;
 	}
 
-	objsize = ALIGN_UP (par_object_get_size (vt, (MonoObject*)obj));
+	objsize = SGEN_ALIGN_UP (mono_sgen_par_object_get_size (vt, (MonoObject*)obj));
 
-	if (objsize > MAX_SMALL_OBJ_SIZE) {
-		if (vtable_word & PINNED_BIT)
+	if (objsize > SGEN_MAX_SMALL_OBJ_SIZE) {
+		if (vtable_word & SGEN_PINNED_BIT)
 			return;
-		binary_protocol_pin (obj, vt, safe_object_get_size ((MonoObject*)obj));
-		if (SGEN_CAS_PTR (obj, (void*)(vtable_word | PINNED_BIT), (void*)vtable_word) == (void*)vtable_word) {
-			if (VTABLE_HAS_REFERENCES (vt))
+		binary_protocol_pin (obj, vt, mono_sgen_safe_object_get_size ((MonoObject*)obj));
+		if (SGEN_CAS_PTR (obj, (void*)(vtable_word | SGEN_PINNED_BIT), (void*)vtable_word) == (void*)vtable_word) {
+			if (SGEN_VTABLE_HAS_REFERENCES (vt))
 				GRAY_OBJECT_ENQUEUE (queue, obj);
 		} else {
-			g_assert (object_is_pinned (obj));
+			g_assert (SGEN_OBJECT_IS_PINNED (obj));
 		}
 		return;
 	}
@@ -637,15 +685,17 @@ major_copy_or_mark_object (void **ptr, GrayQueue *queue)
 	MS_MARK_OBJECT_AND_ENQUEUE (obj, block, queue);
 }
 
+#include "sgen-major-scan-object.h"
+
 static void
-mark_pinned_objects_in_block (MSBlockInfo *block, GrayQueue *queue)
+mark_pinned_objects_in_block (MSBlockInfo *block, SgenGrayQueue *queue)
 {
 	int i;
 	int last_index = -1;
 	int count = MS_BLOCK_FREE / block->obj_size;
 
-	for (i = block->pin_queue_start; i < block->pin_queue_end; ++i) {
-		int index = MS_BLOCK_OBJ_INDEX (pin_queue [i], block);
+	for (i = 0; i < block->pin_queue_num_entries; ++i) {
+		int index = MS_BLOCK_OBJ_INDEX (block->pin_queue_start [i], block);
 		DEBUG (9, g_assert (index >= 0 && index < count));
 		if (index == last_index)
 			continue;
@@ -790,7 +840,7 @@ ms_calculate_block_obj_sizes (double factor, int *arr)
 
 	do {
 		int target_count = ceil (MS_BLOCK_FREE / target_size);
-		int size = MIN ((MS_BLOCK_FREE / target_count) & ~(ALLOC_ALIGN - 1), MAX_SMALL_OBJ_SIZE);
+		int size = MIN ((MS_BLOCK_FREE / target_count) & ~(SGEN_ALLOC_ALIGN - 1), SGEN_MAX_SMALL_OBJ_SIZE);
 
 		if (size != last_size) {
 			if (arr)
@@ -800,45 +850,11 @@ ms_calculate_block_obj_sizes (double factor, int *arr)
 		}
 
 		target_size *= factor;
-	} while (last_size < MAX_SMALL_OBJ_SIZE);
+	} while (last_size < SGEN_MAX_SMALL_OBJ_SIZE);
 
 	return num_sizes;
 }
 
-static void
-major_init (void)
-{
-	int i;
-
-	mono_sgen_register_fixed_internal_mem_type (INTERNAL_MEM_MS_BLOCK_INFO, sizeof (MSBlockInfo));
-
-	num_block_obj_sizes = ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, NULL);
-	block_obj_sizes = mono_sgen_alloc_internal_dynamic (sizeof (int) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
-	ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, block_obj_sizes);
-
-	/*
-	{
-		int i;
-		g_print ("block object sizes:\n");
-		for (i = 0; i < num_block_obj_sizes; ++i)
-			g_print ("%d\n", block_obj_sizes [i]);
-	}
-	*/
-
-	for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i)
-		free_block_lists [i] = mono_sgen_alloc_internal_dynamic (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
-
-	for (i = 0; i < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES; ++i)
-		fast_block_obj_size_indexes [i] = ms_find_block_obj_size_index (i * 8);
-	for (i = 0; i < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES * 8; ++i)
-		g_assert (MS_BLOCK_OBJ_SIZE_INDEX (i) == ms_find_block_obj_size_index (i));
-
-	LOCK_INIT (ms_block_list_mutex);
-
-	mono_counters_register ("# major blocks allocated", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_alloced);
-	mono_counters_register ("# major blocks freed", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_freed);
-}
-
 /* only valid during minor collections */
 static int old_num_major_sections;
 
@@ -855,20 +871,16 @@ major_start_nursery_collection (void)
 static void
 major_finish_nursery_collection (void)
 {
-	int sections_alloced;
-
 #ifdef MARKSWEEP_CONSISTENCY_CHECK
 	consistency_check ();
 #endif
-
-	sections_alloced = num_major_sections - old_num_major_sections;
-	minor_collection_sections_alloced += sections_alloced;
+	mono_sgen_register_major_sections_alloced (num_major_sections - old_num_major_sections);
 }
 
 static void
 major_finish_major_collection (void)
 {
-	int section_reserve = minor_collection_allowance / MS_BLOCK_SIZE;
+	int section_reserve = mono_sgen_get_minor_collection_allowance () / MS_BLOCK_SIZE;
 
 	/*
 	 * FIXME: We don't free blocks on 32 bit platforms because it
@@ -893,18 +905,18 @@ major_finish_major_collection (void)
 }
 
 static void
-major_find_pin_queue_start_ends (GrayQueue *queue)
+major_find_pin_queue_start_ends (SgenGrayQueue *queue)
 {
 	MSBlockInfo *block;
 
 	for (block = all_blocks; block; block = block->next) {
-		find_optimized_pin_queue_area (block->block + MS_BLOCK_SKIP, block->block + MS_BLOCK_SIZE,
-				&block->pin_queue_start, &block->pin_queue_end);
+		block->pin_queue_start = mono_sgen_find_optimized_pin_queue_area (block->block + MS_BLOCK_SKIP, block->block + MS_BLOCK_SIZE,
+				&block->pin_queue_num_entries);
 	}
 }
 
 static void
-major_pin_objects (GrayQueue *queue)
+major_pin_objects (SgenGrayQueue *queue)
 {
 	MSBlockInfo *block;
 
@@ -939,3 +951,76 @@ major_get_used_size (void)
 
 	return size;
 }
+
+static int
+get_num_major_sections (void)
+{
+	return num_major_sections;
+}
+
+void
+mono_sgen_marksweep_init (SgenMajorCollector *collector, int the_nursery_bits, char *the_nursery_start, char *the_nursery_end)
+{
+	int i;
+
+	nursery_bits = the_nursery_bits;
+	nursery_start = the_nursery_start;
+	nursery_end = the_nursery_end;
+
+	mono_sgen_register_fixed_internal_mem_type (INTERNAL_MEM_MS_BLOCK_INFO, sizeof (MSBlockInfo));
+
+	num_block_obj_sizes = ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, NULL);
+	block_obj_sizes = mono_sgen_alloc_internal_dynamic (sizeof (int) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
+	ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, block_obj_sizes);
+
+	/*
+	{
+		int i;
+		g_print ("block object sizes:\n");
+		for (i = 0; i < num_block_obj_sizes; ++i)
+			g_print ("%d\n", block_obj_sizes [i]);
+	}
+	*/
+
+	for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i)
+		free_block_lists [i] = mono_sgen_alloc_internal_dynamic (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
+
+	for (i = 0; i < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES; ++i)
+		fast_block_obj_size_indexes [i] = ms_find_block_obj_size_index (i * 8);
+	for (i = 0; i < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES * 8; ++i)
+		g_assert (MS_BLOCK_OBJ_SIZE_INDEX (i) == ms_find_block_obj_size_index (i));
+
+	LOCK_INIT (ms_block_list_mutex);
+
+	mono_counters_register ("# major blocks allocated", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_alloced);
+	mono_counters_register ("# major blocks freed", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_freed);
+
+	collector->section_size = MAJOR_SECTION_SIZE;
+
+	collector->is_object_live = major_is_object_live;
+	collector->alloc_small_pinned_obj = major_alloc_small_pinned_obj;
+	collector->alloc_degraded = major_alloc_degraded;
+	collector->copy_or_mark_object = major_copy_or_mark_object;
+	collector->alloc_object = major_alloc_object;
+	collector->free_pinned_object = free_pinned_object;
+	collector->iterate_objects = major_iterate_objects;
+	collector->free_non_pinned_object = major_free_non_pinned_object;
+	collector->find_pin_queue_start_ends = major_find_pin_queue_start_ends;
+	collector->pin_objects = major_pin_objects;
+	collector->init_to_space = major_init_to_space;
+	collector->sweep = major_sweep;
+	collector->check_scan_starts = major_check_scan_starts;
+	collector->dump_heap = major_dump_heap;
+	collector->get_used_size = major_get_used_size;
+	collector->start_nursery_collection = major_start_nursery_collection;
+	collector->finish_nursery_collection = major_finish_nursery_collection;
+	collector->finish_major_collection = major_finish_major_collection;
+	collector->ptr_is_in_non_pinned_space = major_ptr_is_in_non_pinned_space;
+	collector->obj_is_from_pinned_alloc = obj_is_from_pinned_alloc;
+	collector->report_pinned_memory_usage = major_report_pinned_memory_usage;
+	collector->get_num_major_sections = get_num_major_sections;
+	FILL_COLLECTOR_COPY_OBJECT (collector);
+	FILL_COLLECTOR_SCAN_OBJECT (collector);
+}
+
+#endif

+ 8 - 3
mono/metadata/sgen-pinning-stats.c

@@ -120,11 +120,16 @@ pin_stats_count_object_from_tree (char *obj, size_t size, PinStatAddress *node,
 		pin_stats_count_object_from_tree (obj, size, node->right, pin_types);
 }
 
-static void
-pin_stats_register_object (char *obj, size_t size)
+void
+mono_sgen_pin_stats_register_object (char *obj, size_t size)
 {
 	int pin_types = 0;
-	ObjectList *list = mono_sgen_alloc_internal_dynamic (sizeof (ObjectList), INTERNAL_MEM_STATISTICS);
+	ObjectList *list;
+
+	if (!heap_dump_file)
+		return;
+
+	list = mono_sgen_alloc_internal_dynamic (sizeof (ObjectList), INTERNAL_MEM_STATISTICS);
 	pin_stats_count_object_from_tree (obj, size, pin_stat_addresses, &pin_types);
 	list->obj = (MonoObject*)obj;
 	list->next = pinned_objects;

+ 6 - 16
mono/metadata/sgen-pinning.c

@@ -106,32 +106,22 @@ optimized_pin_queue_search (void *addr)
 	return first;
 }
 
-static void
-find_optimized_pin_queue_area (void *start, void *end, int *first, int *last)
-{
-	*first = optimized_pin_queue_search (start);
-	*last = optimized_pin_queue_search (end);
-}
-
 void**
 mono_sgen_find_optimized_pin_queue_area (void *start, void *end, int *num)
 {
 	int first, last;
-	find_optimized_pin_queue_area (start, end, &first, &last);
+	first = optimized_pin_queue_search (start);
+	last = optimized_pin_queue_search (end);
 	*num = last - first;
 	if (first == last)
 		return NULL;
 	return pin_queue + first;
 }
 
-static void
-find_section_pin_queue_start_end (GCMemSection *section)
+void
+mono_sgen_find_section_pin_queue_start_end (GCMemSection *section)
 {
-	int start, end;
 	DEBUG (6, fprintf (gc_debug_file, "Pinning from section %p (%p-%p)\n", section, section->data, section->end_data));
-	find_optimized_pin_queue_area (section->data, section->end_data, &start, &end);
-	DEBUG (6, fprintf (gc_debug_file, "Found %d pinning addresses in section %p (%d-%d)\n",
-					end - start, section, start, end));
-	section->pin_queue_start = start;
-	section->pin_queue_end = end;
+	section->pin_queue_start = mono_sgen_find_optimized_pin_queue_area (section->data, section->end_data, &section->pin_queue_num_entries);
+	DEBUG (6, fprintf (gc_debug_file, "Found %d pinning addresses in section %p\n", section->pin_queue_num_entries, section));
 }

+ 21 - 40
mono/metadata/sgen-protocol.c

@@ -21,10 +21,11 @@
  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
-#ifdef BINARY_PROTOCOL
 
 #include "sgen-protocol.h"
 
+#ifdef SGEN_BINARY_PROTOCOL
+
 /* If not null, dump binary protocol to this file */
 static FILE *binary_protocol_file = NULL;
 
@@ -51,7 +52,7 @@ binary_protocol_flush_buffers_rec (BinaryProtocolBuffer *buffer)
 	g_assert (buffer->index > 0);
 	fwrite (buffer->buffer, 1, buffer->index, binary_protocol_file);
 
-	free_os_memory (buffer, sizeof (BinaryProtocolBuffer));
+	mono_sgen_free_os_memory (buffer, sizeof (BinaryProtocolBuffer));
 }
 
 static void
@@ -74,12 +75,12 @@ binary_protocol_get_buffer (int length)
 	if (buffer && buffer->index + length <= BINARY_PROTOCOL_BUFFER_SIZE)
 		return buffer;
 
-	new_buffer = get_os_memory (sizeof (BinaryProtocolBuffer), TRUE);
+	new_buffer = mono_sgen_alloc_os_memory (sizeof (BinaryProtocolBuffer), TRUE);
 	new_buffer->next = buffer;
 	new_buffer->index = 0;
 
 	if (InterlockedCompareExchangePointer ((void**)&binary_protocol_buffers, new_buffer, buffer) != buffer) {
-		free_os_memory (new_buffer, sizeof (BinaryProtocolBuffer));
+		mono_sgen_free_os_memory (new_buffer, sizeof (BinaryProtocolBuffer));
 		goto retry;
 	}
 
@@ -113,7 +114,7 @@ protocol_entry (unsigned char type, gpointer data, int size)
 	g_assert (index <= BINARY_PROTOCOL_BUFFER_SIZE);
 }
 
-static void
+void
 binary_protocol_collection (int generation)
 {
 	SGenProtocolCollection entry = { generation };
@@ -121,84 +122,84 @@ binary_protocol_collection (int generation)
 	protocol_entry (SGEN_PROTOCOL_COLLECTION, &entry, sizeof (SGenProtocolCollection));
 }
 
-static void
+void
 binary_protocol_alloc (gpointer obj, gpointer vtable, int size)
 {
 	SGenProtocolAlloc entry = { obj, vtable, size };
 	protocol_entry (SGEN_PROTOCOL_ALLOC, &entry, sizeof (SGenProtocolAlloc));
 }
 
-static void
+void
 binary_protocol_alloc_pinned (gpointer obj, gpointer vtable, int size)
 {
 	SGenProtocolAlloc entry = { obj, vtable, size };
 	protocol_entry (SGEN_PROTOCOL_ALLOC_PINNED, &entry, sizeof (SGenProtocolAlloc));
 }
 
-static void
+void
 binary_protocol_alloc_degraded (gpointer obj, gpointer vtable, int size)
 {
 	SGenProtocolAlloc entry = { obj, vtable, size };
 	protocol_entry (SGEN_PROTOCOL_ALLOC_DEGRADED, &entry, sizeof (SGenProtocolAlloc));
 }
 
-static void
+void
 binary_protocol_copy (gpointer from, gpointer to, gpointer vtable, int size)
 {
 	SGenProtocolCopy entry = { from, to, vtable, size };
 	protocol_entry (SGEN_PROTOCOL_COPY, &entry, sizeof (SGenProtocolCopy));
 }
 
-static void
+void
 binary_protocol_pin (gpointer obj, gpointer vtable, int size)
 {
 	SGenProtocolPin entry = { obj, vtable, size };
 	protocol_entry (SGEN_PROTOCOL_PIN, &entry, sizeof (SGenProtocolPin));
 }
 
-static void
+void
 binary_protocol_mark (gpointer obj, gpointer vtable, int size)
 {
 	SGenProtocolMark entry = { obj, vtable, size };
 	protocol_entry (SGEN_PROTOCOL_MARK, &entry, sizeof (SGenProtocolMark));
 }
 
-static void
+void
 binary_protocol_wbarrier (gpointer ptr, gpointer value, gpointer value_vtable)
 {
 	SGenProtocolWBarrier entry = { ptr, value, value_vtable };
 	protocol_entry (SGEN_PROTOCOL_WBARRIER, &entry, sizeof (SGenProtocolWBarrier));
 }
 
-static void
+void
 binary_protocol_global_remset (gpointer ptr, gpointer value, gpointer value_vtable)
 {
 	SGenProtocolGlobalRemset entry = { ptr, value, value_vtable };
 	protocol_entry (SGEN_PROTOCOL_GLOBAL_REMSET, &entry, sizeof (SGenProtocolGlobalRemset));
 }
 
-static void
+void
 binary_protocol_ptr_update (gpointer ptr, gpointer old_value, gpointer new_value, gpointer vtable, int size)
 {
 	SGenProtocolPtrUpdate entry = { ptr, old_value, new_value, vtable, size };
 	protocol_entry (SGEN_PROTOCOL_PTR_UPDATE, &entry, sizeof (SGenProtocolPtrUpdate));
 }
 
-static void
+void
 binary_protocol_cleanup (gpointer ptr, gpointer vtable, int size)
 {
 	SGenProtocolCleanup entry = { ptr, vtable, size };
 	protocol_entry (SGEN_PROTOCOL_CLEANUP, &entry, sizeof (SGenProtocolCleanup));
 }
 
-static void
+void
 binary_protocol_empty (gpointer start, int size)
 {
 	SGenProtocolEmpty entry = { start, size };
 	protocol_entry (SGEN_PROTOCOL_EMPTY, &entry, sizeof (SGenProtocolEmpty));
 }
 
-static void
+void
 binary_protocol_thread_restart (gpointer thread)
 {
 	SGenProtocolThreadRestart entry = { thread };
@@ -206,7 +207,7 @@ binary_protocol_thread_restart (gpointer thread)
 
 }
 
-static void
+void
 binary_protocol_thread_register (gpointer thread)
 {
 	SGenProtocolThreadRegister entry = { thread };
@@ -214,7 +215,7 @@ binary_protocol_thread_register (gpointer thread)
 
 }
 
-static void
+void
 binary_protocol_thread_unregister (gpointer thread)
 {
 	SGenProtocolThreadUnregister entry = { thread };
@@ -222,7 +223,7 @@ binary_protocol_thread_unregister (gpointer thread)
 
 }
 
-static void
+void
 binary_protocol_missing_remset (gpointer obj, gpointer obj_vtable, int offset, gpointer value, gpointer value_vtable, int value_pinned)
 {
 	SGenProtocolMissingRemset entry = { obj, obj_vtable, offset, value, value_vtable, value_pinned };
@@ -230,24 +231,4 @@ binary_protocol_missing_remset (gpointer obj, gpointer obj_vtable, int offset, g
 
 }
 
-#else
-
-#define binary_protocol_flush_buffers()
-#define binary_protocol_collection(generation)
-#define binary_protocol_alloc(obj, vtable, size)
-#define binary_protocol_alloc_pinned(obj, vtable, size)
-#define binary_protocol_alloc_degraded(obj, vtable, size)
-#define binary_protocol_copy(from, to, vtable, size)
-#define binary_protocol_pin(obj, vtable, size)
-#define binary_protocol_mark(obj, vtable, size)
-#define binary_protocol_wbarrier(ptr, value, value_vtable)
-#define binary_protocol_global_remset(ptr, value, value_vtable)
-#define binary_protocol_ptr_update(ptr, old_value, new_value, vtable, size)
-#define binary_protocol_cleanup(ptr, vtable, size)
-#define binary_protocol_empty(start, size)
-#define binary_protocol_thread_restart(thread)
-#define binary_protocol_thread_register(thread)
-#define binary_protocol_thread_unregister(thread)
-#define binary_protocol_missing_remset(obj, obj_vtable, offset, value, value_vtable, value_pinned)
-
 #endif

+ 43 - 0
mono/metadata/sgen-protocol.h

@@ -21,6 +21,9 @@
  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
+
+#ifdef SGEN_BINARY_PROTOCOL
+
 enum {
 	SGEN_PROTOCOL_COLLECTION,
 	SGEN_PROTOCOL_ALLOC,
@@ -122,3 +125,43 @@ typedef struct {
 } SGenProtocolMissingRemset;
 
 /* missing: finalizers, dislinks, roots, non-store wbarriers */
+
+void binary_protocol_collection (int generation) MONO_INTERNAL;
+void binary_protocol_alloc (gpointer obj, gpointer vtable, int size) MONO_INTERNAL;
+void binary_protocol_alloc_pinned (gpointer obj, gpointer vtable, int size) MONO_INTERNAL;
+void binary_protocol_alloc_degraded (gpointer obj, gpointer vtable, int size) MONO_INTERNAL;
+void binary_protocol_copy (gpointer from, gpointer to, gpointer vtable, int size) MONO_INTERNAL;
+void binary_protocol_pin (gpointer obj, gpointer vtable, int size) MONO_INTERNAL;
+void binary_protocol_mark (gpointer obj, gpointer vtable, int size) MONO_INTERNAL;
+void binary_protocol_wbarrier (gpointer ptr, gpointer value, gpointer value_vtable) MONO_INTERNAL;
+void binary_protocol_global_remset (gpointer ptr, gpointer value, gpointer value_vtable) MONO_INTERNAL;
+void binary_protocol_ptr_update (gpointer ptr, gpointer old_value, gpointer new_value, gpointer vtable, int size) MONO_INTERNAL;
+void binary_protocol_cleanup (gpointer ptr, gpointer vtable, int size) MONO_INTERNAL;
+void binary_protocol_empty (gpointer start, int size) MONO_INTERNAL;
+void binary_protocol_thread_restart (gpointer thread) MONO_INTERNAL;
+void binary_protocol_thread_register (gpointer thread) MONO_INTERNAL;
+void binary_protocol_thread_unregister (gpointer thread) MONO_INTERNAL;
+void binary_protocol_missing_remset (gpointer obj, gpointer obj_vtable, int offset,
+		gpointer value, gpointer value_vtable, int value_pinned) MONO_INTERNAL;
+
+#else
+
+#define binary_protocol_flush_buffers()
+#define binary_protocol_collection(generation)
+#define binary_protocol_alloc(obj, vtable, size)
+#define binary_protocol_alloc_pinned(obj, vtable, size)
+#define binary_protocol_alloc_degraded(obj, vtable, size)
+#define binary_protocol_copy(from, to, vtable, size)
+#define binary_protocol_pin(obj, vtable, size)
+#define binary_protocol_mark(obj, vtable, size)
+#define binary_protocol_wbarrier(ptr, value, value_vtable)
+#define binary_protocol_global_remset(ptr, value, value_vtable)
+#define binary_protocol_ptr_update(ptr, old_value, new_value, vtable, size)
+#define binary_protocol_cleanup(ptr, vtable, size)
+#define binary_protocol_empty(start, size)
+#define binary_protocol_thread_restart(thread)
+#define binary_protocol_thread_register(thread)
+#define binary_protocol_thread_unregister(thread)
+#define binary_protocol_missing_remset(obj, obj_vtable, offset, value, value_vtable, value_pinned)
+
+#endif

+ 5 - 5
mono/metadata/sgen-scan-object.h

@@ -49,7 +49,7 @@
 	size_t skip_size;
 	mword desc;
 
-	vt = (GCVTable*)LOAD_VTABLE (start);
+	vt = (GCVTable*)SGEN_LOAD_VTABLE (start);
 	//type = vt->desc & 0x7;
 
 	/* gcc should be smart enough to remove the bounds check, but it isn't:( */
@@ -67,7 +67,7 @@
 		break;
 	case DESC_TYPE_ARRAY:
 	case DESC_TYPE_VECTOR:
-		skip_size = ALIGN_UP (safe_object_get_size ((MonoObject*)start));
+		skip_size = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)start));
 #define SCAN OBJ_VECTOR_FOREACH_PTR (vt, start)
 #ifndef SCAN_OBJECT_NOSCAN
 		SCAN;
@@ -88,7 +88,7 @@
 		start += skip_size;
 		break;
 	case DESC_TYPE_LARGE_BITMAP:
-		skip_size = ALIGN_UP (safe_object_get_size ((MonoObject*)start));
+		skip_size = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)start));
 #define SCAN OBJ_LARGE_BITMAP_FOREACH_PTR (vt,start)
 #ifndef SCAN_OBJECT_NOSCAN
 		SCAN;
@@ -99,7 +99,7 @@
 		break;
 	case DESC_TYPE_COMPLEX:
 		/* this is a complex object */
-		skip_size = ALIGN_UP (safe_object_get_size ((MonoObject*)start));
+		skip_size = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)start));
 #define SCAN OBJ_COMPLEX_FOREACH_PTR (vt, start)
 #ifndef SCAN_OBJECT_NOSCAN
 		SCAN;
@@ -110,7 +110,7 @@
 		break;
 	case DESC_TYPE_COMPLEX_ARR:
 		/* this is an array of complex structs */
-		skip_size = ALIGN_UP (safe_object_get_size ((MonoObject*)start));
+		skip_size = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)start));
 #define SCAN OBJ_COMPLEX_ARR_FOREACH_PTR (vt, start)
 #ifndef SCAN_OBJECT_NOSCAN
 		SCAN;

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio