Make nested type loading lazier.
[mono.git] / mono / metadata / sgen-marksweep.c
1 /*
2  * sgen-marksweep.c: Simple generational GC.
3  *
4  * Author:
5  *      Mark Probst <mark.probst@gmail.com>
6  *
7  * Copyright 2009-2010 Novell, Inc.
8  * 
9  * Permission is hereby granted, free of charge, to any person obtaining
10  * a copy of this software and associated documentation files (the
11  * "Software"), to deal in the Software without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  * 
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  * 
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  */
28
29 #ifdef HAVE_SGEN_GC
30
31 #include <math.h>
32
33 #include "utils/mono-counters.h"
34 #include "metadata/object-internals.h"
35 #include "metadata/profiler-private.h"
36
37 #include "metadata/sgen-gc.h"
38 #include "metadata/sgen-protocol.h"
39
40 #define DEBUG(l,x)
41
42 #define MS_BLOCK_SIZE   (16*1024)
43 #define MS_BLOCK_SIZE_SHIFT     14
44 #define MAJOR_SECTION_SIZE      MS_BLOCK_SIZE
45
46 #ifdef FIXED_HEAP
47 #define MS_DEFAULT_HEAP_NUM_BLOCKS      (32 * 1024) /* 512 MB */
48 #endif
49
50 /*
51  * Don't allocate single blocks, but alloc a contingent of this many
52  * blocks in one swoop.
53  */
54 #define MS_BLOCK_ALLOC_NUM      32
55
56 /*
57  * Number of bytes before the first object in a block.  At the start
58  * of a block is the MSBlockHeader, then opional padding, then come
59  * the objects, so this must be >= sizeof (MSBlockHeader).
60  */
61 #ifdef FIXED_HEAP
62 #define MS_BLOCK_SKIP   0
63 #else
64 #define MS_BLOCK_SKIP   16
65 #endif
66
67 #define MS_BLOCK_FREE   (MS_BLOCK_SIZE - MS_BLOCK_SKIP)
68
69 #define MS_NUM_MARK_WORDS       ((MS_BLOCK_SIZE / SGEN_ALLOC_ALIGN + sizeof (mword) * 8 - 1) / (sizeof (mword) * 8))
70
71 #if SGEN_MAX_SMALL_OBJ_SIZE > MS_BLOCK_FREE / 2
72 #error MAX_SMALL_OBJ_SIZE must be at most MS_BLOCK_FREE / 2
73 #endif
74
75 typedef struct _MSBlockInfo MSBlockInfo;
76 struct _MSBlockInfo {
77         int obj_size;
78         gboolean pinned;
79         gboolean has_references;
80 #ifdef FIXED_HEAP
81         gboolean used;
82 #else
83         MSBlockInfo *next;
84 #endif
85         char *block;
86         void **free_list;
87         MSBlockInfo *next_free;
88         void **pin_queue_start;
89         int pin_queue_num_entries;
90         mword mark_words [MS_NUM_MARK_WORDS];
91 };
92
93 #ifdef FIXED_HEAP
94 static int ms_heap_num_blocks = MS_DEFAULT_HEAP_NUM_BLOCKS;
95
96 #define ms_heap_start   nursery_end
97 static char *ms_heap_end;
98
99 #define MS_PTR_IN_SMALL_MAJOR_HEAP(p)   ((char*)(p) >= ms_heap_start && (char*)(p) < ms_heap_end)
100
101 /* array of all all block infos in the system */
102 static MSBlockInfo *block_infos;
103 #endif
104
105 #define MS_BLOCK_OBJ(b,i)               ((b)->block + MS_BLOCK_SKIP + (b)->obj_size * (i))
106 #define MS_BLOCK_DATA_FOR_OBJ(o)        ((char*)((mword)(o) & ~(mword)(MS_BLOCK_SIZE - 1)))
107
108 #ifdef FIXED_HEAP
109 #define MS_BLOCK_FOR_OBJ(o)             (&block_infos [(mword)((char*)(o) - ms_heap_start) >> MS_BLOCK_SIZE_SHIFT])
110 #else
111 typedef struct {
112         MSBlockInfo *info;
113 } MSBlockHeader;
114
115 #define MS_BLOCK_FOR_OBJ(o)             (((MSBlockHeader*)MS_BLOCK_DATA_FOR_OBJ ((o)))->info)
116 #endif
117
118 #define MS_BLOCK_OBJ_INDEX(o,b) (((char*)(o) - ((b)->block + MS_BLOCK_SKIP)) / (b)->obj_size)
119
120 #define MS_CALC_MARK_BIT(w,b,o)         do {                            \
121                 int i = ((char*)(o) - MS_BLOCK_DATA_FOR_OBJ ((o))) >> SGEN_ALLOC_ALIGN_BITS; \
122                 if (sizeof (mword) == 4) {                              \
123                         (w) = i >> 5;                                   \
124                         (b) = i & 31;                                   \
125                 } else {                                                \
126                         (w) = i >> 6;                                   \
127                         (b) = i & 63;                                   \
128                 }                                                       \
129         } while (0)
130
131 #define MS_MARK_BIT(bl,w,b)     ((bl)->mark_words [(w)] & (1L << (b)))
132 #define MS_SET_MARK_BIT(bl,w,b) ((bl)->mark_words [(w)] |= (1L << (b)))
133 #define MS_PAR_SET_MARK_BIT(was_marked,bl,w,b)  do {                    \
134                 mword __old = (bl)->mark_words [(w)];                   \
135                 mword __bitmask = 1L << (b);                            \
136                 if (__old & __bitmask) {                                \
137                         was_marked = TRUE;                              \
138                         break;                                          \
139                 }                                                       \
140                 if (SGEN_CAS_PTR ((gpointer*)&(bl)->mark_words [(w)],   \
141                                                 (gpointer)(__old | __bitmask), \
142                                                 (gpointer)__old) ==     \
143                                 (gpointer)__old) {                      \
144                         was_marked = FALSE;                             \
145                         break;                                          \
146                 }                                                       \
147         } while (1)
148
149 #define MS_OBJ_ALLOCED(o,b)     (*(void**)(o) && (*(char**)(o) < (b)->block || *(char**)(o) >= (b)->block + MS_BLOCK_SIZE))
150
151 #define MS_BLOCK_OBJ_SIZE_FACTOR        (sqrt (2.0))
152
153 /*
154  * This way we can lookup block object size indexes for sizes up to
155  * 256 bytes with a single load.
156  */
157 #define MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES      32
158
159 static int *block_obj_sizes;
160 static int num_block_obj_sizes;
161 static int fast_block_obj_size_indexes [MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES];
162
163 #define MS_BLOCK_FLAG_PINNED    1
164 #define MS_BLOCK_FLAG_REFS      2
165
166 #define MS_BLOCK_TYPE_MAX       4
167
168 #ifdef SGEN_PARALLEL_MARK
169 static LOCK_DECLARE (ms_block_list_mutex);
170 #define LOCK_MS_BLOCK_LIST pthread_mutex_lock (&ms_block_list_mutex)
171 #define UNLOCK_MS_BLOCK_LIST pthread_mutex_unlock (&ms_block_list_mutex)
172 #else
173 #define LOCK_MS_BLOCK_LIST
174 #define UNLOCK_MS_BLOCK_LIST
175 #endif
176
177 /* we get this at init */
178 static int nursery_bits;
179 static char *nursery_start;
180 static char *nursery_end;
181
182 #define ptr_in_nursery(p)       (SGEN_PTR_IN_NURSERY ((p), nursery_bits, nursery_start, nursery_end))
183
184 #ifdef FIXED_HEAP
185 /* non-allocated block free-list */
186 static MSBlockInfo *empty_blocks = NULL;
187 #else
188 /* non-allocated block free-list */
189 static void *empty_blocks = NULL;
190 /* all allocated blocks in the system */
191 static MSBlockInfo *all_blocks;
192 static int num_empty_blocks = 0;
193 #endif
194
195 #ifdef FIXED_HEAP
196 #define FOREACH_BLOCK(bl)       {                                       \
197                 int __block_i;                                          \
198                 for (__block_i = 0; __block_i < ms_heap_num_blocks; ++__block_i) { \
199                         (bl) = &block_infos [__block_i];                \
200                         if (!(bl)->used) continue;
201 #define END_FOREACH_BLOCK       }}
202 #else
203 #define FOREACH_BLOCK(bl)       for ((bl) = all_blocks; (bl); (bl) = (bl)->next) {
204 #define END_FOREACH_BLOCK       }
205 #endif
206
207 static int num_major_sections = 0;
208 /* one free block list for each block object size */
209 static MSBlockInfo **free_block_lists [MS_BLOCK_TYPE_MAX];
210
211 static long long stat_major_blocks_alloced = 0;
212 static long long stat_major_blocks_freed = 0;
213
214 static int
215 ms_find_block_obj_size_index (int size)
216 {
217         int i;
218         DEBUG (9, g_assert (size <= SGEN_MAX_SMALL_OBJ_SIZE));
219         for (i = 0; i < num_block_obj_sizes; ++i)
220                 if (block_obj_sizes [i] >= size)
221                         return i;
222         g_assert_not_reached ();
223 }
224
225 #define FREE_BLOCKS(p,r) (free_block_lists [((p) ? MS_BLOCK_FLAG_PINNED : 0) | ((r) ? MS_BLOCK_FLAG_REFS : 0)])
226
227 #define MS_BLOCK_OBJ_SIZE_INDEX(s)                              \
228         (((s)+7)>>3 < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES ?      \
229          fast_block_obj_size_indexes [((s)+7)>>3] :             \
230          ms_find_block_obj_size_index ((s)))
231
232 #ifdef FIXED_HEAP
233 static void*
234 major_alloc_heap (mword nursery_size, mword nursery_align, int the_nursery_bits)
235 {
236         char *heap_start;
237         mword major_heap_size = ms_heap_num_blocks * MS_BLOCK_SIZE;
238         mword alloc_size = nursery_size + major_heap_size;
239         int i;
240
241         g_assert (ms_heap_num_blocks > 0);
242         g_assert (nursery_size % MS_BLOCK_SIZE == 0);
243         if (nursery_align)
244                 g_assert (nursery_align % MS_BLOCK_SIZE == 0);
245
246         nursery_start = mono_sgen_alloc_os_memory_aligned (alloc_size, nursery_align ? nursery_align : MS_BLOCK_SIZE, TRUE);
247         nursery_end = heap_start = nursery_start + nursery_size;
248         nursery_bits = the_nursery_bits;
249
250         ms_heap_end = heap_start + major_heap_size;
251
252         block_infos = mono_sgen_alloc_internal_dynamic (sizeof (MSBlockInfo) * ms_heap_num_blocks, INTERNAL_MEM_MS_BLOCK_INFO);
253
254         for (i = 0; i < ms_heap_num_blocks; ++i) {
255                 block_infos [i].block = heap_start + i * MS_BLOCK_SIZE;
256                 if (i < ms_heap_num_blocks - 1)
257                         block_infos [i].next_free = &block_infos [i + 1];
258                 else
259                         block_infos [i].next_free = NULL;
260         }
261
262         empty_blocks = &block_infos [0];
263
264         return nursery_start;
265 }
266 #else
267 static void*
268 major_alloc_heap (mword nursery_size, mword nursery_align, int the_nursery_bits)
269 {
270         if (nursery_align)
271                 nursery_start = mono_sgen_alloc_os_memory_aligned (nursery_size, nursery_align, TRUE);
272         else
273                 nursery_start = mono_sgen_alloc_os_memory (nursery_size, TRUE);
274
275         nursery_end = nursery_start + nursery_size;
276         nursery_bits = the_nursery_bits;
277
278         return nursery_start;
279 }
280 #endif
281
282 #ifdef FIXED_HEAP
283 static MSBlockInfo*
284 ms_get_empty_block (void)
285 {
286         MSBlockInfo *block;
287
288         g_assert (empty_blocks);
289
290         block = empty_blocks;
291         empty_blocks = empty_blocks->next_free;
292
293         block->used = TRUE;
294
295         mono_sgen_update_heap_boundaries ((mword)block, (mword)block + MS_BLOCK_SIZE);
296
297         return block;
298 }
299
300 static void
301 ms_free_block (MSBlockInfo *block)
302 {
303         block->next_free = empty_blocks;
304         empty_blocks = block;
305         block->used = FALSE;
306 }
307 #else
308 static void*
309 ms_get_empty_block (void)
310 {
311         char *p;
312         int i;
313         void *block, *empty, *next;
314
315  retry:
316         if (!empty_blocks) {
317                 p = mono_sgen_alloc_os_memory_aligned (MS_BLOCK_SIZE * MS_BLOCK_ALLOC_NUM, MS_BLOCK_SIZE, TRUE);
318
319                 for (i = 0; i < MS_BLOCK_ALLOC_NUM; ++i) {
320                         block = p;
321                         /*
322                          * We do the free list update one after the
323                          * other so that other threads can use the new
324                          * blocks as quickly as possible.
325                          */
326                         do {
327                                 empty = empty_blocks;
328                                 *(void**)block = empty;
329                         } while (SGEN_CAS_PTR (&empty_blocks, block, empty) != empty);
330                         p += MS_BLOCK_SIZE;
331                 }
332
333                 SGEN_ATOMIC_ADD (num_empty_blocks, MS_BLOCK_ALLOC_NUM);
334
335                 stat_major_blocks_alloced += MS_BLOCK_ALLOC_NUM;
336         }
337
338         do {
339                 empty = empty_blocks;
340                 if (!empty)
341                         goto retry;
342                 block = empty;
343                 next = *(void**)block;
344         } while (SGEN_CAS_PTR (&empty_blocks, next, empty) != empty);
345
346         SGEN_ATOMIC_ADD (num_empty_blocks, -1);
347
348         *(void**)block = NULL;
349
350         g_assert (!((mword)block & (MS_BLOCK_SIZE - 1)));
351
352         mono_sgen_update_heap_boundaries ((mword)block, (mword)block + MS_BLOCK_SIZE);
353
354         return block;
355 }
356
357 static void
358 ms_free_block (void *block)
359 {
360         void *empty;
361
362         memset (block, 0, MS_BLOCK_SIZE);
363
364         do {
365                 empty = empty_blocks;
366                 *(void**)block = empty;
367         } while (SGEN_CAS_PTR (&empty_blocks, block, empty) != empty);
368
369         SGEN_ATOMIC_ADD (num_empty_blocks, 1);
370 }
371 #endif
372
373 //#define MARKSWEEP_CONSISTENCY_CHECK
374
375 #ifdef MARKSWEEP_CONSISTENCY_CHECK
376 static void
377 check_block_free_list (MSBlockInfo *block, int size, gboolean pinned)
378 {
379         MSBlockInfo *b;
380
381         for (; block; block = block->next_free) {
382                 g_assert (block->obj_size == size);
383                 g_assert ((pinned && block->pinned) || (!pinned && !block->pinned));
384
385                 /* blocks in the free lists must have at least
386                    one free slot */
387                 g_assert (block->free_list);
388
389 #ifdef FIXED_HEAP
390                 /* the block must not be in the empty_blocks list */
391                 for (b = empty_blocks; b; b = b->next_free)
392                         g_assert (b != block);
393 #else
394                 /* the block must be in the all_blocks list */
395                 for (b = all_blocks; b; b = b->next) {
396                         if (b == block)
397                                 break;
398                 }
399                 g_assert (b == block);
400 #endif
401         }
402 }
403
404 static void
405 check_empty_blocks (void)
406 {
407 #ifndef FIXED_HEAP
408         void *p;
409         int i = 0;
410         for (p = empty_blocks; p; p = *(void**)p)
411                 ++i;
412         g_assert (i == num_empty_blocks);
413 #endif
414 }
415
416 static void
417 consistency_check (void)
418 {
419         MSBlockInfo *block;
420         int i;
421
422         /* check all blocks */
423         FOREACH_BLOCK (block) {
424                 int count = MS_BLOCK_FREE / block->obj_size;
425                 int num_free = 0;
426                 void **free;
427
428 #ifndef FIXED_HEAP
429                 /* check block header */
430                 g_assert (((MSBlockHeader*)block->block)->info == block);
431 #endif
432
433                 /* count number of free slots */
434                 for (i = 0; i < count; ++i) {
435                         void **obj = (void**) MS_BLOCK_OBJ (block, i);
436                         if (!MS_OBJ_ALLOCED (obj, block))
437                                 ++num_free;
438                 }
439
440                 /* check free list */
441                 for (free = block->free_list; free; free = (void**)*free) {
442                         g_assert (MS_BLOCK_FOR_OBJ (free) == block);
443                         --num_free;
444                 }
445                 g_assert (num_free == 0);
446
447                 /* check all mark words are zero */
448                 for (i = 0; i < MS_NUM_MARK_WORDS; ++i)
449                         g_assert (block->mark_words [i] == 0);
450         } END_FOREACH_BLOCK;
451
452         /* check free blocks */
453         for (i = 0; i < num_block_obj_sizes; ++i) {
454                 int j;
455                 for (j = 0; j < MS_BLOCK_TYPE_MAX; ++j)
456                         check_block_free_list (free_block_lists [j][i], block_obj_sizes [i], j & MS_BLOCK_FLAG_PINNED);
457         }
458
459         check_empty_blocks ();
460 }
461 #endif
462
463 static void
464 ms_alloc_block (int size_index, gboolean pinned, gboolean has_references)
465 {
466         int size = block_obj_sizes [size_index];
467         int count = MS_BLOCK_FREE / size;
468 #ifdef FIXED_HEAP
469         MSBlockInfo *info = ms_get_empty_block ();
470 #else
471         MSBlockInfo *info = mono_sgen_alloc_internal (INTERNAL_MEM_MS_BLOCK_INFO);
472         MSBlockHeader *header;
473 #endif
474         MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, has_references);
475         char *obj_start;
476         int i;
477
478         DEBUG (9, g_assert (count >= 2));
479
480         info->obj_size = size;
481         info->pinned = pinned;
482         info->has_references = has_references;
483 #ifndef FIXED_HEAP
484         info->block = ms_get_empty_block ();
485
486         header = (MSBlockHeader*) info->block;
487         header->info = info;
488 #endif
489
490         /* build free list */
491         obj_start = info->block + MS_BLOCK_SKIP;
492         info->free_list = (void**)obj_start;
493         /* we're skipping the last one - it must be nulled */
494         for (i = 0; i < count - 1; ++i) {
495                 char *next_obj_start = obj_start + size;
496                 *(void**)obj_start = next_obj_start;
497                 obj_start = next_obj_start;
498         }
499         /* the last one */
500         *(void**)obj_start = NULL;
501
502         info->next_free = free_blocks [size_index];
503         free_blocks [size_index] = info;
504
505 #ifndef FIXED_HEAP
506         info->next = all_blocks;
507         all_blocks = info;
508 #endif
509
510         ++num_major_sections;
511 }
512
513 static gboolean
514 obj_is_from_pinned_alloc (char *obj)
515 {
516         MSBlockInfo *block = MS_BLOCK_FOR_OBJ (obj);
517         return block->pinned;
518 }
519
520 static void*
521 alloc_obj (int size, gboolean pinned, gboolean has_references)
522 {
523         int size_index = MS_BLOCK_OBJ_SIZE_INDEX (size);
524         MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, has_references);
525         MSBlockInfo *block;
526         void *obj;
527
528         /* FIXME: try to do this without locking */
529
530         LOCK_MS_BLOCK_LIST;
531
532         if (!free_blocks [size_index])
533                 ms_alloc_block (size_index, pinned, has_references);
534
535         block = free_blocks [size_index];
536         DEBUG (9, g_assert (block));
537
538         obj = block->free_list;
539         DEBUG (9, g_assert (obj));
540
541         block->free_list = *(void**)obj;
542         if (!block->free_list) {
543                 free_blocks [size_index] = block->next_free;
544                 block->next_free = NULL;
545         }
546
547         UNLOCK_MS_BLOCK_LIST;
548
549         /*
550          * FIXME: This should not be necessary because it'll be
551          * overwritten by the vtable immediately.
552          */
553         *(void**)obj = NULL;
554
555         return obj;
556 }
557
558 static void*
559 major_alloc_object (int size, gboolean has_references)
560 {
561         return alloc_obj (size, FALSE, has_references);
562 }
563
564 /*
565  * We're not freeing the block if it's empty.  We leave that work for
566  * the next major collection.
567  *
568  * This is just called from the domain clearing code, which runs in a
569  * single thread and has the GC lock, so we don't need an extra lock.
570  */
571 static void
572 free_object (char *obj, size_t size, gboolean pinned)
573 {
574         MSBlockInfo *block = MS_BLOCK_FOR_OBJ (obj);
575         int word, bit;
576         DEBUG (9, g_assert ((pinned && block->pinned) || (!pinned && !block->pinned)));
577         DEBUG (9, g_assert (MS_OBJ_ALLOCED (obj, block)));
578         MS_CALC_MARK_BIT (word, bit, obj);
579         DEBUG (9, g_assert (!MS_MARK_BIT (block, word, bit)));
580         if (!block->free_list) {
581                 MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, block->has_references);
582                 int size_index = MS_BLOCK_OBJ_SIZE_INDEX (size);
583                 DEBUG (9, g_assert (!block->next_free));
584                 block->next_free = free_blocks [size_index];
585                 free_blocks [size_index] = block;
586         }
587         memset (obj, 0, size);
588         *(void**)obj = block->free_list;
589         block->free_list = (void**)obj;
590 }
591
592 static void
593 major_free_non_pinned_object (char *obj, size_t size)
594 {
595         free_object (obj, size, FALSE);
596 }
597
598 /* size is a multiple of SGEN_ALLOC_ALIGN */
599 static void*
600 major_alloc_small_pinned_obj (size_t size, gboolean has_references)
601 {
602         return alloc_obj (size, TRUE, has_references);
603 }
604
605 static void
606 free_pinned_object (char *obj, size_t size)
607 {
608         free_object (obj, size, TRUE);
609 }
610
611 /*
612  * size is already rounded up and we hold the GC lock.
613  */
614 static void*
615 major_alloc_degraded (MonoVTable *vtable, size_t size)
616 {
617         void *obj;
618         int old_num_sections = num_major_sections;
619         obj = alloc_obj (size, FALSE, vtable->klass->has_references);
620         *(MonoVTable**)obj = vtable;
621         HEAVY_STAT (++stat_objects_alloced_degraded);
622         HEAVY_STAT (stat_bytes_alloced_degraded += size);
623         g_assert (num_major_sections >= old_num_sections);
624         mono_sgen_register_major_sections_alloced (num_major_sections - old_num_sections);
625         return obj;
626 }
627
628 #define MAJOR_OBJ_IS_IN_TO_SPACE(obj)   FALSE
629
630 /*
631  * obj is some object.  If it's not in the major heap (i.e. if it's in
632  * the nursery or LOS), return FALSE.  Otherwise return whether it's
633  * been marked or copied.
634  */
635 static gboolean
636 major_is_object_live (char *obj)
637 {
638         MSBlockInfo *block;
639         int word, bit;
640 #ifndef FIXED_HEAP
641         mword objsize;
642 #endif
643
644         if (ptr_in_nursery (obj))
645                 return FALSE;
646
647 #ifdef FIXED_HEAP
648         /* LOS */
649         if (!MS_PTR_IN_SMALL_MAJOR_HEAP (obj))
650                 return FALSE;
651 #else
652         objsize = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)obj));
653
654         /* LOS */
655         if (objsize > SGEN_MAX_SMALL_OBJ_SIZE)
656                 return FALSE;
657 #endif
658
659         /* now we know it's in a major block */
660         block = MS_BLOCK_FOR_OBJ (obj);
661         DEBUG (9, g_assert (!block->pinned));
662         MS_CALC_MARK_BIT (word, bit, obj);
663         return MS_MARK_BIT (block, word, bit) ? TRUE : FALSE;
664 }
665
666 static gboolean
667 major_ptr_is_in_non_pinned_space (char *ptr)
668 {
669         g_assert_not_reached ();
670 }
671
672 static void
673 major_iterate_objects (gboolean non_pinned, gboolean pinned, IterateObjectCallbackFunc callback, void *data)
674 {
675         MSBlockInfo *block;
676
677         FOREACH_BLOCK (block) {
678                 int count = MS_BLOCK_FREE / block->obj_size;
679                 int i;
680
681                 if (block->pinned && !pinned)
682                         continue;
683                 if (!block->pinned && !non_pinned)
684                         continue;
685
686                 for (i = 0; i < count; ++i) {
687                         void **obj = (void**) MS_BLOCK_OBJ (block, i);
688                         if (MS_OBJ_ALLOCED (obj, block))
689                                 callback ((char*)obj, block->obj_size, data);
690                 }
691         } END_FOREACH_BLOCK;
692 }
693
694 static void
695 major_check_scan_starts (void)
696 {
697 }
698
699 static void
700 major_dump_heap (FILE *heap_dump_file)
701 {
702         MSBlockInfo *block;
703
704         FOREACH_BLOCK (block) {
705                 int count = MS_BLOCK_FREE / block->obj_size;
706                 int i;
707                 int start = -1;
708
709                 fprintf (heap_dump_file, "<section type=\"%s\" size=\"%zu\">\n", "old", (size_t)MS_BLOCK_FREE);
710
711                 for (i = 0; i <= count; ++i) {
712                         if ((i < count) && MS_OBJ_ALLOCED (MS_BLOCK_OBJ (block, i), block)) {
713                                 if (start < 0)
714                                         start = i;
715                         } else {
716                                 if (start >= 0) {
717                                         mono_sgen_dump_occupied (MS_BLOCK_OBJ (block, start), MS_BLOCK_OBJ (block, i), block->block);
718                                         start = -1;
719                                 }
720                         }
721                 }
722
723                 fprintf (heap_dump_file, "</section>\n");
724         } END_FOREACH_BLOCK;
725 }
726
727 #define LOAD_VTABLE     SGEN_LOAD_VTABLE
728
729 #define MS_MARK_OBJECT_AND_ENQUEUE_CHECKED(obj,block,queue) do {        \
730                 int __word, __bit;                                      \
731                 MS_CALC_MARK_BIT (__word, __bit, (obj));                \
732                 if (!MS_MARK_BIT ((block), __word, __bit) && MS_OBJ_ALLOCED ((obj), (block))) { \
733                         MS_SET_MARK_BIT ((block), __word, __bit);       \
734                         if ((block)->has_references)                    \
735                                 GRAY_OBJECT_ENQUEUE ((queue), (obj));   \
736                         binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), mono_sgen_safe_object_get_size ((MonoObject*)(obj))); \
737                 }                                                       \
738         } while (0)
739 #define MS_MARK_OBJECT_AND_ENQUEUE(obj,block,queue) do {                \
740                 int __word, __bit;                                      \
741                 MS_CALC_MARK_BIT (__word, __bit, (obj));                \
742                 DEBUG (9, g_assert (MS_OBJ_ALLOCED ((obj), (block))));  \
743                 if (!MS_MARK_BIT ((block), __word, __bit)) {            \
744                         MS_SET_MARK_BIT ((block), __word, __bit);       \
745                         if ((block)->has_references)                    \
746                                 GRAY_OBJECT_ENQUEUE ((queue), (obj));   \
747                         binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), mono_sgen_safe_object_get_size ((MonoObject*)(obj))); \
748                 }                                                       \
749         } while (0)
750 #define MS_PAR_MARK_OBJECT_AND_ENQUEUE(obj,block,queue) do {            \
751                 int __word, __bit;                                      \
752                 gboolean __was_marked;                                  \
753                 DEBUG (9, g_assert (MS_OBJ_ALLOCED ((obj), (block))));  \
754                 MS_CALC_MARK_BIT (__word, __bit, (obj));                \
755                 MS_PAR_SET_MARK_BIT (__was_marked, (block), __word, __bit); \
756                 if (!__was_marked) {                                    \
757                         if ((block)->has_references)                    \
758                                 GRAY_OBJECT_ENQUEUE ((queue), (obj));   \
759                         binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), mono_sgen_safe_object_get_size ((MonoObject*)(obj))); \
760                 }                                                       \
761         } while (0)
762
763 #include "sgen-major-copy-object.h"
764
765 #ifdef SGEN_PARALLEL_MARK
766 static void
767 major_copy_or_mark_object (void **ptr, SgenGrayQueue *queue)
768 {
769         void *obj = *ptr;
770         mword vtable_word = *(mword*)obj;
771         MonoVTable *vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
772         mword objsize;
773         MSBlockInfo *block;
774
775         HEAVY_STAT (++stat_copy_object_called_major);
776
777         DEBUG (9, g_assert (obj));
778         DEBUG (9, g_assert (current_collection_generation == GENERATION_OLD));
779
780         if (ptr_in_nursery (obj)) {
781                 int word, bit;
782                 gboolean has_references;
783                 void *destination;
784
785                 if (vtable_word & SGEN_FORWARDED_BIT) {
786                         *ptr = (void*)vt;
787                         return;
788                 }
789
790                 if (vtable_word & SGEN_PINNED_BIT)
791                         return;
792
793                 HEAVY_STAT (++stat_objects_copied_major);
794
795                 objsize = SGEN_ALIGN_UP (mono_sgen_par_object_get_size (vt, (MonoObject*)obj));
796                 has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
797
798                 destination = major_alloc_object (objsize, has_references);
799
800                 if (SGEN_CAS_PTR (obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) {
801                         gboolean was_marked;
802
803                         par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL);
804                         obj = destination;
805                         *ptr = obj;
806
807                         /*
808                          * FIXME: If we make major_alloc_object() give
809                          * us the block info, too, we won't have to
810                          * re-fetch it here.
811                          */
812                         block = MS_BLOCK_FOR_OBJ (obj);
813                         MS_CALC_MARK_BIT (word, bit, obj);
814                         DEBUG (9, g_assert (!MS_MARK_BIT (block, word, bit)));
815                         MS_PAR_SET_MARK_BIT (was_marked, block, word, bit);
816                 } else {
817                         /*
818                          * FIXME: We have allocated destination, but
819                          * we cannot use it.  Give it back to the
820                          * allocator.
821                          */
822                         *(void**)destination = NULL;
823
824                         vtable_word = *(mword*)obj;
825                         g_assert (vtable_word & SGEN_FORWARDED_BIT);
826
827                         obj = (void*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
828
829                         *ptr = obj;
830                 }
831         } else {
832 #ifdef FIXED_HEAP
833                 if (MS_PTR_IN_SMALL_MAJOR_HEAP (obj))
834 #else
835                 objsize = SGEN_ALIGN_UP (mono_sgen_par_object_get_size (vt, (MonoObject*)obj));
836
837                 if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE)
838 #endif
839                 {
840                         block = MS_BLOCK_FOR_OBJ (obj);
841                         MS_PAR_MARK_OBJECT_AND_ENQUEUE (obj, block, queue);
842                 } else {
843                         if (vtable_word & SGEN_PINNED_BIT)
844                                 return;
845                         binary_protocol_pin (obj, vt, mono_sgen_safe_object_get_size ((MonoObject*)obj));
846                         if (SGEN_CAS_PTR (obj, (void*)(vtable_word | SGEN_PINNED_BIT), (void*)vtable_word) == (void*)vtable_word) {
847                                 if (SGEN_VTABLE_HAS_REFERENCES (vt))
848                                         GRAY_OBJECT_ENQUEUE (queue, obj);
849                         } else {
850                                 g_assert (SGEN_OBJECT_IS_PINNED (obj));
851                         }
852                 }
853         }
854 }
855 #else
856 static void
857 major_copy_or_mark_object (void **ptr, SgenGrayQueue *queue)
858 {
859         void *obj = *ptr;
860         mword objsize;
861         MSBlockInfo *block;
862
863         HEAVY_STAT (++stat_copy_object_called_major);
864
865         DEBUG (9, g_assert (obj));
866         DEBUG (9, g_assert (current_collection_generation == GENERATION_OLD));
867
868         if (ptr_in_nursery (obj)) {
869                 int word, bit;
870                 char *forwarded;
871
872                 if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) {
873                         *ptr = forwarded;
874                         return;
875                 }
876                 if (SGEN_OBJECT_IS_PINNED (obj))
877                         return;
878
879                 HEAVY_STAT (++stat_objects_copied_major);
880
881                 obj = copy_object_no_checks (obj, queue);
882                 *ptr = obj;
883
884                 /*
885                  * FIXME: See comment for copy_object_no_checks().  If
886                  * we have that, we can let the allocation function
887                  * give us the block info, too, and we won't have to
888                  * re-fetch it.
889                  */
890                 block = MS_BLOCK_FOR_OBJ (obj);
891                 MS_CALC_MARK_BIT (word, bit, obj);
892                 DEBUG (9, g_assert (!MS_MARK_BIT (block, word, bit)));
893                 MS_SET_MARK_BIT (block, word, bit);
894         } else {
895 #ifdef FIXED_HEAP
896                 if (MS_PTR_IN_SMALL_MAJOR_HEAP (obj))
897 #else
898                 objsize = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)obj));
899
900                 if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE)
901 #endif
902                 {
903                         block = MS_BLOCK_FOR_OBJ (obj);
904                         MS_MARK_OBJECT_AND_ENQUEUE (obj, block, queue);
905                 } else {
906                         if (SGEN_OBJECT_IS_PINNED (obj))
907                                 return;
908                         binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), mono_sgen_safe_object_get_size ((MonoObject*)obj));
909                         SGEN_PIN_OBJECT (obj);
910                         /* FIXME: only enqueue if object has references */
911                         GRAY_OBJECT_ENQUEUE (queue, obj);
912                 }
913         }
914 }
915 #endif
916
917 #include "sgen-major-scan-object.h"
918
919 static void
920 mark_pinned_objects_in_block (MSBlockInfo *block, SgenGrayQueue *queue)
921 {
922         int i;
923         int last_index = -1;
924         int count = MS_BLOCK_FREE / block->obj_size;
925
926         for (i = 0; i < block->pin_queue_num_entries; ++i) {
927                 int index = MS_BLOCK_OBJ_INDEX (block->pin_queue_start [i], block);
928                 DEBUG (9, g_assert (index >= 0 && index < count));
929                 if (index == last_index)
930                         continue;
931                 MS_MARK_OBJECT_AND_ENQUEUE_CHECKED (MS_BLOCK_OBJ (block, index), block, queue);
932                 last_index = index;
933         }
934 }
935
936 static void
937 major_sweep (void)
938 {
939         int i;
940 #ifdef FIXED_HEAP
941         int j;
942 #else
943         MSBlockInfo **iter;
944 #endif
945
946         /* clear all the free lists */
947         for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i) {
948                 MSBlockInfo **free_blocks = free_block_lists [i];
949                 int j;
950                 for (j = 0; j < num_block_obj_sizes; ++j)
951                         free_blocks [j] = NULL;
952         }
953
954         /* traverse all blocks, free and zero unmarked objects */
955 #ifdef FIXED_HEAP
956         for (j = 0; j < ms_heap_num_blocks; ++j) {
957                 MSBlockInfo *block = &block_infos [j];
958 #else
959         iter = &all_blocks;
960         while (*iter) {
961                 MSBlockInfo *block = *iter;
962 #endif
963                 int count;
964                 gboolean have_live = FALSE;
965                 int obj_index;
966
967 #ifdef FIXED_HEAP
968                 if (!block->used)
969                         continue;
970 #endif
971
972                 count = MS_BLOCK_FREE / block->obj_size;
973                 block->free_list = NULL;
974
975                 for (obj_index = 0; obj_index < count; ++obj_index) {
976                         int word, bit;
977                         void *obj = MS_BLOCK_OBJ (block, obj_index);
978
979                         MS_CALC_MARK_BIT (word, bit, obj);
980                         if (MS_MARK_BIT (block, word, bit)) {
981                                 DEBUG (9, g_assert (MS_OBJ_ALLOCED (obj, block)));
982                                 have_live = TRUE;
983                         } else {
984                                 /* an unmarked object */
985                                 if (MS_OBJ_ALLOCED (obj, block)) {
986                                         binary_protocol_empty (obj, block->obj_size);
987                                         memset (obj, 0, block->obj_size);
988                                 }
989                                 *(void**)obj = block->free_list;
990                                 block->free_list = obj;
991                         }
992                 }
993
994                 /* reset mark bits */
995                 memset (block->mark_words, 0, sizeof (mword) * MS_NUM_MARK_WORDS);
996
997                 /*
998                  * FIXME: reverse free list so that it's in address
999                  * order
1000                  */
1001
1002                 if (have_live) {
1003 #ifndef FIXED_HEAP
1004                         iter = &block->next;
1005 #endif
1006
1007                         /*
1008                          * If there are free slots in the block, add
1009                          * the block to the corresponding free list.
1010                          */
1011                         if (block->free_list) {
1012                                 MSBlockInfo **free_blocks = FREE_BLOCKS (block->pinned, block->has_references);
1013                                 int index = MS_BLOCK_OBJ_SIZE_INDEX (block->obj_size);
1014                                 block->next_free = free_blocks [index];
1015                                 free_blocks [index] = block;
1016                         }
1017                 } else {
1018                         /*
1019                          * Blocks without live objects are removed from the
1020                          * block list and freed.
1021                          */
1022 #ifdef FIXED_HEAP
1023                         ms_free_block (block);
1024 #else
1025                         *iter = block->next;
1026
1027                         ms_free_block (block->block);
1028                         mono_sgen_free_internal (block, INTERNAL_MEM_MS_BLOCK_INFO);
1029 #endif
1030
1031                         --num_major_sections;
1032                 }
1033         }
1034 }
1035
1036 static int count_pinned_ref;
1037 static int count_pinned_nonref;
1038 static int count_nonpinned_ref;
1039 static int count_nonpinned_nonref;
1040
1041 static void
1042 count_nonpinned_callback (char *obj, size_t size, void *data)
1043 {
1044         MonoVTable *vtable = (MonoVTable*)LOAD_VTABLE (obj);
1045
1046         if (vtable->klass->has_references)
1047                 ++count_nonpinned_ref;
1048         else
1049                 ++count_nonpinned_nonref;
1050 }
1051
1052 static void
1053 count_pinned_callback (char *obj, size_t size, void *data)
1054 {
1055         MonoVTable *vtable = (MonoVTable*)LOAD_VTABLE (obj);
1056
1057         if (vtable->klass->has_references)
1058                 ++count_pinned_ref;
1059         else
1060                 ++count_pinned_nonref;
1061 }
1062
1063 static void __attribute__ ((unused))
1064 count_ref_nonref_objs (void)
1065 {
1066         int total;
1067
1068         count_pinned_ref = 0;
1069         count_pinned_nonref = 0;
1070         count_nonpinned_ref = 0;
1071         count_nonpinned_nonref = 0;
1072
1073         major_iterate_objects (TRUE, FALSE, count_nonpinned_callback, NULL);
1074         major_iterate_objects (FALSE, TRUE, count_pinned_callback, NULL);
1075
1076         total = count_pinned_nonref + count_nonpinned_nonref + count_pinned_ref + count_nonpinned_ref;
1077
1078         g_print ("ref: %d pinned %d non-pinned   non-ref: %d pinned %d non-pinned  --  %.1f\n",
1079                         count_pinned_ref, count_nonpinned_ref,
1080                         count_pinned_nonref, count_nonpinned_nonref,
1081                         (count_pinned_nonref + count_nonpinned_nonref) * 100.0 / total);
1082 }
1083
1084 static int
1085 ms_calculate_block_obj_sizes (double factor, int *arr)
1086 {
1087         double target_size = sizeof (MonoObject);
1088         int num_sizes = 0;
1089         int last_size = 0;
1090
1091         do {
1092                 int target_count = ceil (MS_BLOCK_FREE / target_size);
1093                 int size = MIN ((MS_BLOCK_FREE / target_count) & ~(SGEN_ALLOC_ALIGN - 1), SGEN_MAX_SMALL_OBJ_SIZE);
1094
1095                 if (size != last_size) {
1096                         if (arr)
1097                                 arr [num_sizes] = size;
1098                         ++num_sizes;
1099                         last_size = size;
1100                 }
1101
1102                 target_size *= factor;
1103         } while (last_size < SGEN_MAX_SMALL_OBJ_SIZE);
1104
1105         return num_sizes;
1106 }
1107
1108 /* only valid during minor collections */
1109 static int old_num_major_sections;
1110
1111 static void
1112 major_start_nursery_collection (void)
1113 {
1114 #ifdef MARKSWEEP_CONSISTENCY_CHECK
1115         consistency_check ();
1116 #endif
1117
1118         old_num_major_sections = num_major_sections;
1119 }
1120
1121 static void
1122 major_finish_nursery_collection (void)
1123 {
1124 #ifdef MARKSWEEP_CONSISTENCY_CHECK
1125         consistency_check ();
1126 #endif
1127         mono_sgen_register_major_sections_alloced (num_major_sections - old_num_major_sections);
1128 }
1129
1130 static void
1131 major_finish_major_collection (void)
1132 {
1133 #ifndef FIXED_HEAP
1134         int section_reserve = mono_sgen_get_minor_collection_allowance () / MS_BLOCK_SIZE;
1135
1136         /*
1137          * FIXME: We don't free blocks on 32 bit platforms because it
1138          * can lead to address space fragmentation, since we're
1139          * allocating blocks in larger contingents.
1140          */
1141         if (sizeof (mword) < 8)
1142                 return;
1143
1144         while (num_empty_blocks > section_reserve) {
1145                 void *next = *(void**)empty_blocks;
1146                 mono_sgen_free_os_memory (empty_blocks, MS_BLOCK_SIZE);
1147                 empty_blocks = next;
1148                 /*
1149                  * Needs not be atomic because this is running
1150                  * single-threaded.
1151                  */
1152                 --num_empty_blocks;
1153
1154                 ++stat_major_blocks_freed;
1155         }
1156 #endif
1157 }
1158
1159 static void
1160 major_find_pin_queue_start_ends (SgenGrayQueue *queue)
1161 {
1162         MSBlockInfo *block;
1163
1164         FOREACH_BLOCK (block) {
1165                 block->pin_queue_start = mono_sgen_find_optimized_pin_queue_area (block->block + MS_BLOCK_SKIP, block->block + MS_BLOCK_SIZE,
1166                                 &block->pin_queue_num_entries);
1167         } END_FOREACH_BLOCK;
1168 }
1169
1170 static void
1171 major_pin_objects (SgenGrayQueue *queue)
1172 {
1173         MSBlockInfo *block;
1174
1175         FOREACH_BLOCK (block) {
1176                 mark_pinned_objects_in_block (block, queue);
1177         } END_FOREACH_BLOCK;
1178 }
1179
1180 static void
1181 major_init_to_space (void)
1182 {
1183 }
1184
1185 static void
1186 major_report_pinned_memory_usage (void)
1187 {
1188         g_assert_not_reached ();
1189 }
1190
1191 static gint64
1192 major_get_used_size (void)
1193 {
1194         gint64 size = 0;
1195         MSBlockInfo *block;
1196
1197         FOREACH_BLOCK (block) {
1198                 int count = MS_BLOCK_FREE / block->obj_size;
1199                 void **iter;
1200                 size += count * block->obj_size;
1201                 for (iter = block->free_list; iter; iter = (void**)*iter)
1202                         size -= block->obj_size;
1203         } END_FOREACH_BLOCK;
1204
1205         return size;
1206 }
1207
1208 static int
1209 get_num_major_sections (void)
1210 {
1211         return num_major_sections;
1212 }
1213
1214 #ifdef FIXED_HEAP
1215 static gboolean
1216 major_handle_gc_param (const char *opt)
1217 {
1218         if (g_str_has_prefix (opt, "major-heap-size=")) {
1219                 const char *arg = strchr (opt, '=') + 1;
1220                 glong size;
1221                 if (!mono_sgen_parse_environment_string_extract_number (arg, &size))
1222                         return FALSE;
1223                 ms_heap_num_blocks = (size + MS_BLOCK_SIZE - 1) / MS_BLOCK_SIZE;
1224                 g_assert (ms_heap_num_blocks > 0);
1225                 return TRUE;
1226         }
1227
1228         return FALSE;
1229 }
1230
1231 static void
1232 major_print_gc_param_usage (void)
1233 {
1234         fprintf (stderr, "  major-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
1235 }
1236 #endif
1237
1238 void
1239 #ifdef SGEN_PARALLEL_MARK
1240 #ifdef FIXED_HEAP
1241 mono_sgen_marksweep_fixed_par_init
1242 #else
1243 mono_sgen_marksweep_par_init
1244 #endif
1245 #else
1246 #ifdef FIXED_HEAP
1247 mono_sgen_marksweep_fixed_init
1248 #else
1249 mono_sgen_marksweep_init
1250 #endif
1251 #endif
1252         (SgenMajorCollector *collector)
1253 {
1254         int i;
1255
1256 #ifndef FIXED_HEAP
1257         mono_sgen_register_fixed_internal_mem_type (INTERNAL_MEM_MS_BLOCK_INFO, sizeof (MSBlockInfo));
1258 #endif
1259
1260         num_block_obj_sizes = ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, NULL);
1261         block_obj_sizes = mono_sgen_alloc_internal_dynamic (sizeof (int) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
1262         ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, block_obj_sizes);
1263
1264         /*
1265         {
1266                 int i;
1267                 g_print ("block object sizes:\n");
1268                 for (i = 0; i < num_block_obj_sizes; ++i)
1269                         g_print ("%d\n", block_obj_sizes [i]);
1270         }
1271         */
1272
1273         for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i)
1274                 free_block_lists [i] = mono_sgen_alloc_internal_dynamic (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
1275
1276         for (i = 0; i < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES; ++i)
1277                 fast_block_obj_size_indexes [i] = ms_find_block_obj_size_index (i * 8);
1278         for (i = 0; i < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES * 8; ++i)
1279                 g_assert (MS_BLOCK_OBJ_SIZE_INDEX (i) == ms_find_block_obj_size_index (i));
1280
1281         LOCK_INIT (ms_block_list_mutex);
1282
1283         mono_counters_register ("# major blocks allocated", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_alloced);
1284         mono_counters_register ("# major blocks freed", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_freed);
1285
1286         collector->section_size = MAJOR_SECTION_SIZE;
1287 #ifdef SGEN_PARALLEL_MARK
1288         collector->is_parallel = TRUE;
1289 #else
1290         collector->is_parallel = FALSE;
1291 #endif
1292
1293         collector->alloc_heap = major_alloc_heap;
1294         collector->is_object_live = major_is_object_live;
1295         collector->alloc_small_pinned_obj = major_alloc_small_pinned_obj;
1296         collector->alloc_degraded = major_alloc_degraded;
1297         collector->copy_or_mark_object = major_copy_or_mark_object;
1298         collector->alloc_object = major_alloc_object;
1299         collector->free_pinned_object = free_pinned_object;
1300         collector->iterate_objects = major_iterate_objects;
1301         collector->free_non_pinned_object = major_free_non_pinned_object;
1302         collector->find_pin_queue_start_ends = major_find_pin_queue_start_ends;
1303         collector->pin_objects = major_pin_objects;
1304         collector->init_to_space = major_init_to_space;
1305         collector->sweep = major_sweep;
1306         collector->check_scan_starts = major_check_scan_starts;
1307         collector->dump_heap = major_dump_heap;
1308         collector->get_used_size = major_get_used_size;
1309         collector->start_nursery_collection = major_start_nursery_collection;
1310         collector->finish_nursery_collection = major_finish_nursery_collection;
1311         collector->finish_major_collection = major_finish_major_collection;
1312         collector->ptr_is_in_non_pinned_space = major_ptr_is_in_non_pinned_space;
1313         collector->obj_is_from_pinned_alloc = obj_is_from_pinned_alloc;
1314         collector->report_pinned_memory_usage = major_report_pinned_memory_usage;
1315         collector->get_num_major_sections = get_num_major_sections;
1316 #ifdef FIXED_HEAP
1317         collector->handle_gc_param = major_handle_gc_param;
1318         collector->print_gc_param_usage = major_print_gc_param_usage;
1319 #else
1320         collector->handle_gc_param = NULL;
1321         collector->print_gc_param_usage = NULL;
1322 #endif
1323
1324         FILL_COLLECTOR_COPY_OBJECT (collector);
1325         FILL_COLLECTOR_SCAN_OBJECT (collector);
1326 }
1327
1328 #endif