Merge pull request #90 from nulltoken/patch-1.
[mono.git] / mono / metadata / sgen-major-copying.c
1 /*
2  * sgen-major-copying.c: Simple generational GC.
3  *
4  * Author:
5  *      Paolo Molaro (lupus@ximian.com)
6  *
7  * Copyright 2005-2010 Novell, Inc (http://www.novell.com)
8  *
9  * Thread start/stop adapted from Boehm's GC:
10  * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
11  * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
12  * Copyright (c) 1998 by Fergus Henderson.  All rights reserved.
13  * Copyright (c) 2000-2004 by Hewlett-Packard Company.  All rights reserved.
14  *
15  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
16  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
17  *
18  * Permission is hereby granted to use or copy this program
19  * for any purpose,  provided the above notices are retained on all copies.
20  * Permission to modify the code and to distribute modified code is granted,
21  * provided the above notices are retained, and a notice that the code was
22  * modified is included with the above copyright notice.
23  *
24  *
25  * Copyright 2001-2003 Ximian, Inc
26  * Copyright 2003-2010 Novell, Inc.
27  * 
28  * Permission is hereby granted, free of charge, to any person obtaining
29  * a copy of this software and associated documentation files (the
30  * "Software"), to deal in the Software without restriction, including
31  * without limitation the rights to use, copy, modify, merge, publish,
32  * distribute, sublicense, and/or sell copies of the Software, and to
33  * permit persons to whom the Software is furnished to do so, subject to
34  * the following conditions:
35  * 
36  * The above copyright notice and this permission notice shall be
37  * included in all copies or substantial portions of the Software.
38  * 
39  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
40  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
41  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
42  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
43  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
44  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
45  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46  */
47
48 #ifdef HAVE_SGEN_GC
49
50 #include "utils/mono-counters.h"
51
52 #include "metadata/sgen-gc.h"
53 #include "metadata/sgen-protocol.h"
54 #include "metadata/mono-gc.h"
55 #include "metadata/object-internals.h"
56 #include "metadata/profiler-private.h"
57
58 #define MAJOR_SECTION_SIZE              SGEN_PINNED_CHUNK_SIZE
59 #define BLOCK_FOR_OBJECT(o)             SGEN_PINNED_CHUNK_FOR_PTR ((o))
60 #define MAJOR_SECTION_FOR_OBJECT(o)     ((GCMemSection*)BLOCK_FOR_OBJECT ((o)))
61
62 #define MAJOR_OBJ_IS_IN_TO_SPACE(o)     (MAJOR_SECTION_FOR_OBJECT ((o))->is_to_space)
63
64 static int num_major_sections = 0;
65
66 static GCMemSection *section_list = NULL;
67
68 static SgenPinnedAllocator pinned_allocator;
69
70 static gboolean have_swept;
71
72 /*
73  * used when moving the objects
74  */
75 static char *to_space_bumper = NULL;
76 static char *to_space_top = NULL;
77 static GCMemSection *to_space_section = NULL;
78
79 /* we get this at init */
80 static int nursery_bits;
81 static char *nursery_start;
82 static char *nursery_end;
83
84 #define ptr_in_nursery(p)       (SGEN_PTR_IN_NURSERY ((p), nursery_bits, nursery_start, nursery_end))
85
86 #ifdef HEAVY_STATISTICS
87 static long stat_major_copy_object_failed_forwarded = 0;
88 static long stat_major_copy_object_failed_pinned = 0;
89 static long stat_major_copy_object_failed_large_pinned = 0;
90 static long stat_major_copy_object_failed_to_space = 0;
91 #endif
92
93 static void*
94 major_alloc_heap (mword nursery_size, mword nursery_align, int the_nursery_bits)
95 {
96         if (nursery_align)
97                 nursery_start = mono_sgen_alloc_os_memory_aligned (nursery_size, nursery_align, TRUE);
98         else
99                 nursery_start = mono_sgen_alloc_os_memory (nursery_size, TRUE);
100
101         nursery_end = nursery_start + nursery_size;
102         nursery_bits = the_nursery_bits;
103
104         return nursery_start;
105 }
106
107 static gboolean
108 obj_is_from_pinned_alloc (char *p)
109 {
110         return BLOCK_FOR_OBJECT (p)->role == MEMORY_ROLE_PINNED;
111 }
112
113 static void
114 free_pinned_object (char *obj, size_t size)
115 {
116         mono_sgen_free_pinned (&pinned_allocator, obj, size);
117 }
118
119 /*
120  * Allocate a new section of memory to be used as old generation.
121  */
122 static GCMemSection*
123 alloc_major_section (void)
124 {
125         GCMemSection *section;
126         int scan_starts;
127
128         section = mono_sgen_alloc_os_memory_aligned (MAJOR_SECTION_SIZE, MAJOR_SECTION_SIZE, TRUE);
129         section->next_data = section->data = (char*)section + SGEN_SIZEOF_GC_MEM_SECTION;
130         g_assert (!((mword)section->data & 7));
131         section->size = MAJOR_SECTION_SIZE - SGEN_SIZEOF_GC_MEM_SECTION;
132         section->end_data = section->data + section->size;
133         mono_sgen_update_heap_boundaries ((mword)section->data, (mword)section->end_data);
134         DEBUG (3, fprintf (gc_debug_file, "New major heap section: (%p-%p), total: %jd\n", section->data, section->end_data, mono_gc_get_heap_size ()));
135         scan_starts = (section->size + SGEN_SCAN_START_SIZE - 1) / SGEN_SCAN_START_SIZE;
136         section->scan_starts = mono_sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS);
137         section->num_scan_start = scan_starts;
138         section->block.role = MEMORY_ROLE_GEN1;
139         section->is_to_space = TRUE;
140
141         /* add to the section list */
142         section->block.next = section_list;
143         section_list = section;
144
145         ++num_major_sections;
146
147         return section;
148 }
149
150 static void
151 free_major_section (GCMemSection *section)
152 {
153         DEBUG (3, fprintf (gc_debug_file, "Freed major section %p (%p-%p)\n", section, section->data, section->end_data));
154         mono_sgen_free_internal_dynamic (section->scan_starts,
155                         (section->size + SGEN_SCAN_START_SIZE - 1) / SGEN_SCAN_START_SIZE * sizeof (char*), INTERNAL_MEM_SCAN_STARTS);
156         mono_sgen_free_os_memory (section, MAJOR_SECTION_SIZE);
157
158         --num_major_sections;
159 }
160
161 static void
162 new_to_space_section (void)
163 {
164         /* FIXME: if the current to_space_section is empty, we don't
165            have to allocate a new one */
166
167         to_space_section = alloc_major_section ();
168         to_space_bumper = to_space_section->next_data;
169         to_space_top = to_space_section->end_data;
170 }
171
172 static void
173 to_space_set_next_data (void)
174 {
175         g_assert (to_space_bumper >= to_space_section->next_data && to_space_bumper <= to_space_section->end_data);
176         to_space_section->next_data = to_space_bumper;
177 }
178
179 static void
180 to_space_expand (void)
181 {
182         if (to_space_section) {
183                 g_assert (to_space_top == to_space_section->end_data);
184                 to_space_set_next_data ();
185         }
186
187         new_to_space_section ();
188 }
189
190 static void*
191 major_alloc_object (int size, gboolean has_references)
192 {
193         char *dest = to_space_bumper;
194         /* Make sure we have enough space available */
195         if (dest + size > to_space_top) {
196                 to_space_expand ();
197                 (dest) = to_space_bumper;
198                 DEBUG (8, g_assert (dest + size <= to_space_top));
199         }
200         to_space_bumper += size;
201         DEBUG (8, g_assert (to_space_bumper <= to_space_top));
202         to_space_section->scan_starts [(dest - (char*)to_space_section->data)/SGEN_SCAN_START_SIZE] = dest;
203         return dest;
204 }
205
206 static void
207 unset_to_space (void)
208 {
209         /* between collections the to_space_bumper is invalidated
210            because degraded allocations might occur, so we set it to
211            NULL, just to make it explicit */
212         to_space_bumper = NULL;
213
214         /* don't unset to_space_section if we implement the FIXME in
215            new_to_space_section */
216         to_space_section = NULL;
217 }
218
219 static gboolean
220 major_is_object_live (char *obj)
221 {
222         mword objsize;
223
224         /* nursery */
225         if (ptr_in_nursery (obj))
226                 return FALSE;
227
228         objsize = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)obj));
229
230         /* LOS */
231         if (objsize > SGEN_MAX_SMALL_OBJ_SIZE)
232                 return FALSE;
233
234         /* pinned chunk */
235         if (obj_is_from_pinned_alloc (obj))
236                 return FALSE;
237
238         /* now we know it's in a major heap section */
239         return MAJOR_SECTION_FOR_OBJECT (obj)->is_to_space;
240 }
241
242 /* size is a multiple of ALLOC_ALIGN */
243 static void*
244 major_alloc_small_pinned_obj (size_t size, gboolean has_references)
245 {
246         return mono_sgen_alloc_pinned (&pinned_allocator, size);
247 }
248
249 /*
250  * size is already rounded up and we hold the GC lock.
251  */
252 static void*
253 major_alloc_degraded (MonoVTable *vtable, size_t size)
254 {
255         GCMemSection *section;
256         void **p = NULL;
257         g_assert (size <= SGEN_MAX_SMALL_OBJ_SIZE);
258         HEAVY_STAT (++stat_objects_alloced_degraded);
259         HEAVY_STAT (stat_bytes_alloced_degraded += size);
260         for (section = section_list; section; section = section->block.next) {
261                 if ((section->end_data - section->next_data) >= size) {
262                         p = (void**)section->next_data;
263                         break;
264                 }
265         }
266         if (!p) {
267                 section = alloc_major_section ();
268                 section->is_to_space = FALSE;
269                 /* FIXME: handle OOM */
270                 p = (void**)section->next_data;
271                 mono_sgen_register_major_sections_alloced (1);
272         }
273         section->next_data += size;
274         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));
275         *p = vtable;
276         return p;
277 }
278
279 #include "sgen-major-copy-object.h"
280
281 static void
282 major_copy_or_mark_object (void **obj_slot, SgenGrayQueue *queue)
283 {
284         char *forwarded;
285         char *obj = *obj_slot;
286         mword objsize;
287
288         DEBUG (9, g_assert (current_collection_generation == GENERATION_OLD));
289
290         HEAVY_STAT (++stat_copy_object_called_major);
291
292         DEBUG (9, fprintf (gc_debug_file, "Precise copy of %p from %p", obj, obj_slot));
293
294         /*
295          * obj must belong to one of:
296          *
297          * 1. the nursery
298          * 2. the LOS
299          * 3. a pinned chunk
300          * 4. a non-to-space section of the major heap
301          * 5. a to-space section of the major heap
302          *
303          * In addition, objects in 1, 2 and 4 might also be pinned.
304          * Objects in 1 and 4 might be forwarded.
305          *
306          * Before we can copy the object we must make sure that we are
307          * allowed to, i.e. that the object not pinned, not already
308          * forwarded and doesn't belong to the LOS, a pinned chunk, or
309          * a to-space section.
310          *
311          * We are usually called for to-space objects (5) when we have
312          * two remset entries for the same reference.  The first entry
313          * copies the object and updates the reference and the second
314          * calls us with the updated reference that points into
315          * to-space.  There might also be other circumstances where we
316          * get to-space objects.
317          */
318
319         if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) {
320                 DEBUG (9, g_assert (((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr));
321                 DEBUG (9, fprintf (gc_debug_file, " (already forwarded to %p)\n", forwarded));
322                 HEAVY_STAT (++stat_major_copy_object_failed_forwarded);
323                 *obj_slot = forwarded;
324                 return;
325         }
326         if (SGEN_OBJECT_IS_PINNED (obj)) {
327                 DEBUG (9, g_assert (((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr));
328                 DEBUG (9, fprintf (gc_debug_file, " (pinned, no change)\n"));
329                 HEAVY_STAT (++stat_major_copy_object_failed_pinned);
330                 return;
331         }
332
333         if (ptr_in_nursery (obj))
334                 goto copy;
335
336         /*
337          * At this point we know obj is not pinned, not forwarded and
338          * belongs to 2, 3, 4, or 5.
339          *
340          * LOS object (2) are simple, at least until we always follow
341          * the rule: if objsize > SGEN_MAX_SMALL_OBJ_SIZE, pin the
342          * object and return it.  At the end of major collections, we
343          * walk the los list and if the object is pinned, it is
344          * marked, otherwise it can be freed.
345          *
346          * Pinned chunks (3) and major heap sections (4, 5) both
347          * reside in blocks, which are always aligned, so once we've
348          * eliminated LOS objects, we can just access the block and
349          * see whether it's a pinned chunk or a major heap section.
350          */
351
352         objsize = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)obj));
353
354         if (G_UNLIKELY (objsize > SGEN_MAX_SMALL_OBJ_SIZE || obj_is_from_pinned_alloc (obj))) {
355                 if (SGEN_OBJECT_IS_PINNED (obj))
356                         return;
357                 DEBUG (9, fprintf (gc_debug_file, " (marked LOS/Pinned %p (%s), size: %zd)\n", obj, mono_sgen_safe_name (obj), objsize));
358                 binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), mono_sgen_safe_object_get_size ((MonoObject*)obj));
359                 SGEN_PIN_OBJECT (obj);
360                 GRAY_OBJECT_ENQUEUE (queue, obj);
361                 HEAVY_STAT (++stat_major_copy_object_failed_large_pinned);
362                 return;
363         }
364
365         /*
366          * Now we know the object is in a major heap section.  All we
367          * need to do is check whether it's already in to-space (5) or
368          * not (4).
369          */
370         if (MAJOR_OBJ_IS_IN_TO_SPACE (obj)) {
371                 DEBUG (9, g_assert (objsize <= SGEN_MAX_SMALL_OBJ_SIZE));
372                 DEBUG (9, fprintf (gc_debug_file, " (already copied)\n"));
373                 HEAVY_STAT (++stat_major_copy_object_failed_to_space);
374                 return;
375         }
376
377  copy:
378         HEAVY_STAT (++stat_objects_copied_major);
379
380         *obj_slot = copy_object_no_checks (obj, queue);
381 }
382
383 #include "sgen-major-scan-object.h"
384
385 /* FIXME: later reduce code duplication here with build_nursery_fragments().
386  * We don't keep track of section fragments for non-nursery sections yet, so
387  * just memset to 0.
388  */
389 static void
390 build_section_fragments (GCMemSection *section)
391 {
392         int i;
393         char *frag_start, *frag_end;
394         size_t frag_size;
395
396         /* clear scan starts */
397         memset (section->scan_starts, 0, section->num_scan_start * sizeof (gpointer));
398         frag_start = section->data;
399         section->next_data = section->data;
400         for (i = 0; i < section->pin_queue_num_entries; ++i) {
401                 frag_end = section->pin_queue_start [i];
402                 /* remove the pin bit from pinned objects */
403                 SGEN_UNPIN_OBJECT (frag_end);
404                 if (frag_end >= section->data + section->size) {
405                         frag_end = section->data + section->size;
406                 } else {
407                         section->scan_starts [((char*)frag_end - (char*)section->data)/SGEN_SCAN_START_SIZE] = frag_end;
408                 }
409                 frag_size = frag_end - frag_start;
410                 if (frag_size) {
411                         binary_protocol_empty (frag_start, frag_size);
412                         memset (frag_start, 0, frag_size);
413                 }
414                 frag_size = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)section->pin_queue_start [i]));
415                 frag_start = (char*)section->pin_queue_start [i] + frag_size;
416                 section->next_data = MAX (section->next_data, frag_start);
417         }
418         frag_end = section->end_data;
419         frag_size = frag_end - frag_start;
420         if (frag_size) {
421                 binary_protocol_empty (frag_start, frag_size);
422                 memset (frag_start, 0, frag_size);
423         }
424 }
425
426 static void
427 sweep_pinned_objects_callback (char *ptr, size_t size, void *data)
428 {
429         if (SGEN_OBJECT_IS_PINNED (ptr)) {
430                 SGEN_UNPIN_OBJECT (ptr);
431                 DEBUG (6, fprintf (gc_debug_file, "Unmarked pinned object %p (%s)\n", ptr, mono_sgen_safe_name (ptr)));
432         } else {
433                 DEBUG (6, fprintf (gc_debug_file, "Freeing unmarked pinned object %p (%s)\n", ptr, mono_sgen_safe_name (ptr)));
434                 free_pinned_object (ptr, size);
435         }
436 }
437
438 static void
439 sweep_pinned_objects (void)
440 {
441         mono_sgen_pinned_scan_objects (&pinned_allocator, sweep_pinned_objects_callback, NULL);
442 }
443
444 static void
445 major_iterate_objects (gboolean non_pinned, gboolean pinned, IterateObjectCallbackFunc callback, void *data)
446 {
447         if (non_pinned) {
448                 GCMemSection *section;
449                 for (section = section_list; section; section = section->block.next)
450                         mono_sgen_scan_area_with_callback (section->data, section->end_data, callback, data, FALSE);
451         }
452         if (pinned)
453                 mono_sgen_pinned_scan_objects (&pinned_allocator, callback, data);
454 }
455
456 static void
457 major_free_non_pinned_object (char *obj, size_t size)
458 {
459         memset (obj, 0, size);
460 }
461
462 static void
463 pin_pinned_object_callback (void *addr, size_t slot_size, SgenGrayQueue *queue)
464 {
465         binary_protocol_pin (addr, (gpointer)SGEN_LOAD_VTABLE (addr), mono_sgen_safe_object_get_size ((MonoObject*)addr));
466         if (!SGEN_OBJECT_IS_PINNED (addr))
467                 mono_sgen_pin_stats_register_object ((char*) addr, mono_sgen_safe_object_get_size ((MonoObject*) addr));
468         SGEN_PIN_OBJECT (addr);
469         GRAY_OBJECT_ENQUEUE (queue, addr);
470         DEBUG (6, fprintf (gc_debug_file, "Marked pinned object %p (%s) from roots\n", addr, mono_sgen_safe_name (addr)));
471 }
472
473 static void
474 major_find_pin_queue_start_ends (SgenGrayQueue *queue)
475 {
476         GCMemSection *section;
477
478         for (section = section_list; section; section = section->block.next)
479                 mono_sgen_find_section_pin_queue_start_end (section);
480         mono_sgen_pinned_scan_pinned_objects (&pinned_allocator, (IterateObjectCallbackFunc)pin_pinned_object_callback, queue);
481 }
482
483 static void
484 major_pin_objects (SgenGrayQueue *queue)
485 {
486         GCMemSection *section;
487
488         for (section = section_list; section; section = section->block.next)
489                 mono_sgen_pin_objects_in_section (section, queue);
490 }
491
492 static void
493 major_init_to_space (void)
494 {
495         new_to_space_section ();
496 }
497
498 static void
499 major_sweep (void)
500 {
501         GCMemSection *section, *prev_section;
502
503         to_space_set_next_data ();
504         unset_to_space ();
505
506         /* unpin objects from the pinned chunks and free the unmarked ones */
507         sweep_pinned_objects ();
508
509         mono_sgen_pinned_update_heap_boundaries (&pinned_allocator);
510
511         /* free the unused sections */
512         prev_section = NULL;
513         for (section = section_list; section;) {
514                 GCMemSection *this_section = section;
515
516                 /* to_space doesn't need handling here */
517                 if (section->is_to_space) {
518                         section->is_to_space = FALSE;
519                         prev_section = section;
520                         section = section->block.next;
521                         goto update;
522                 }
523                 /* no pinning object, so the section is free */
524                 if (!section->pin_queue_num_entries) {
525                         GCMemSection *to_free;
526                         g_assert (!section->pin_queue_start);
527                         if (prev_section)
528                                 prev_section->block.next = section->block.next;
529                         else
530                                 section_list = section->block.next;
531                         to_free = section;
532                         section = section->block.next;
533                         free_major_section (to_free);
534                         continue;
535                 } else {
536                         DEBUG (6, fprintf (gc_debug_file, "Section %p has still pinned objects (%d)\n", section, section->pin_queue_num_entries));
537                         build_section_fragments (section);
538                 }
539                 prev_section = section;
540                 section = section->block.next;
541
542         update:
543                 mono_sgen_update_heap_boundaries ((mword)this_section->data, (mword)this_section->data + this_section->size);
544         }
545
546         have_swept = TRUE;
547 }
548
549 static void
550 major_check_scan_starts (void)
551 {
552         GCMemSection *section;
553         for (section = section_list; section; section = section->block.next)
554                 mono_sgen_check_section_scan_starts (section);
555 }
556
557 static void
558 major_dump_heap (FILE *heap_dump_file)
559 {
560         GCMemSection *section;
561         for (section = section_list; section; section = section->block.next)
562                 mono_sgen_dump_section (section, "old");
563         /* FIXME: dump pinned sections, too */
564 }
565
566 static gint64
567 major_get_used_size (void)
568 {
569         gint64 tot = 0;
570         GCMemSection *section;
571         for (section = section_list; section; section = section->block.next) {
572                 /* this is approximate... */
573                 tot += section->next_data - section->data;
574         }
575         return tot;
576 }
577
578 /* only valid during minor collections */
579 static int old_num_major_sections;
580
581 static void
582 major_start_nursery_collection (void)
583 {
584         old_num_major_sections = num_major_sections;
585
586         if (!to_space_section) {
587                 new_to_space_section ();
588         } else {
589                 /* we might have done degraded allocation since the
590                    last collection */
591                 g_assert (to_space_bumper <= to_space_section->next_data);
592                 to_space_bumper = to_space_section->next_data;
593
594                 to_space_section->is_to_space = TRUE;
595         }
596 }
597
598 static void
599 major_finish_nursery_collection (void)
600 {
601         GCMemSection *section;
602         int sections_alloced;
603
604         to_space_set_next_data ();
605
606         for (section = section_list; section; section = section->block.next)
607                 section->is_to_space = FALSE;
608
609         sections_alloced = num_major_sections - old_num_major_sections;
610         mono_sgen_register_major_sections_alloced (sections_alloced);
611 }
612
613 static void
614 major_finish_major_collection (void)
615 {
616 }
617
618 static gboolean
619 major_ptr_is_in_non_pinned_space (char *ptr)
620 {
621         GCMemSection *section;
622         for (section = section_list; section;) {
623                 if (ptr >= section->data && ptr < section->data + section->size)
624                         return TRUE;
625                 section = section->block.next;
626         }
627         return FALSE;
628 }
629
630 static void
631 major_report_pinned_memory_usage (void)
632 {
633         mono_sgen_report_pinned_mem_usage (&pinned_allocator);
634 }
635
636 static int
637 get_num_major_sections (void)
638 {
639         return num_major_sections;
640 }
641
642 void
643 mono_sgen_copying_init (SgenMajorCollector *collector)
644 {
645 #ifdef HEAVY_STATISTICS
646         mono_counters_register ("# major copy_object() failed forwarded", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_forwarded);
647         mono_counters_register ("# major copy_object() failed pinned", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_pinned);
648         mono_counters_register ("# major copy_object() failed large or pinned chunk", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_large_pinned);
649         mono_counters_register ("# major copy_object() failed to space", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_copy_object_failed_to_space);
650 #endif
651
652         collector->section_size = MAJOR_SECTION_SIZE;
653         collector->supports_cardtable = FALSE;
654         collector->is_parallel = FALSE;
655
656         collector->have_swept = &have_swept;
657
658         collector->alloc_heap = major_alloc_heap;
659         collector->is_object_live = major_is_object_live;
660         collector->alloc_small_pinned_obj = major_alloc_small_pinned_obj;
661         collector->alloc_degraded = major_alloc_degraded;
662         collector->copy_or_mark_object = major_copy_or_mark_object;
663         collector->alloc_object = major_alloc_object;
664         collector->free_pinned_object = free_pinned_object;
665         collector->iterate_objects = major_iterate_objects;
666         collector->free_non_pinned_object = major_free_non_pinned_object;
667         collector->find_pin_queue_start_ends = major_find_pin_queue_start_ends;
668         collector->pin_objects = major_pin_objects;
669         collector->init_to_space = major_init_to_space;
670         collector->sweep = major_sweep;
671         collector->check_scan_starts = major_check_scan_starts;
672         collector->dump_heap = major_dump_heap;
673         collector->get_used_size = major_get_used_size;
674         collector->start_nursery_collection = major_start_nursery_collection;
675         collector->finish_nursery_collection = major_finish_nursery_collection;
676         collector->finish_major_collection = major_finish_major_collection;
677         collector->ptr_is_in_non_pinned_space = major_ptr_is_in_non_pinned_space;
678         collector->obj_is_from_pinned_alloc = obj_is_from_pinned_alloc;
679         collector->report_pinned_memory_usage = major_report_pinned_memory_usage;
680         collector->get_num_major_sections = get_num_major_sections;
681         collector->handle_gc_param = NULL;
682         collector->print_gc_param_usage = NULL;
683
684         FILL_COLLECTOR_COPY_OBJECT (collector);
685         FILL_COLLECTOR_SCAN_OBJECT (collector);
686 }
687
688 #endif