Merge branch 'master' of https://github.com/mono/mono
[mono.git] / mono / metadata / sgen-cardtable.c
1 /*
2  * sgen-cardtable.c: Card table implementation for sgen
3  *
4  * Author:
5  *      Rodrigo Kumpera (rkumpera@novell.com)
6  *
7  * Copyright 2001-2003 Ximian, Inc
8  * Copyright 2003-2010 Novell, Inc.
9  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
10  * Copyright (C) 2012 Xamarin Inc
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License 2.0 as published by the Free Software Foundation;
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public
22  * License 2.0 along with this library; if not, write to the Free
23  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 #include "config.h"
27 #ifdef HAVE_SGEN_GC
28
29 #include "metadata/sgen-gc.h"
30 #include "metadata/sgen-cardtable.h"
31 #include "metadata/sgen-memory-governor.h"
32 #include "metadata/sgen-protocol.h"
33 #include "metadata/sgen-layout-stats.h"
34 #include "utils/mono-counters.h"
35 #include "utils/mono-time.h"
36 #include "utils/mono-memory-model.h"
37
38 //#define CARDTABLE_STATS
39
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #ifdef HAVE_SYS_MMAN_H
44 #include <sys/mman.h>
45 #endif
46 #include <sys/types.h>
47
48 guint8 *sgen_cardtable;
49
50 static gboolean need_mod_union;
51
52 #ifdef HEAVY_STATISTICS
53 long long marked_cards;
54 long long scanned_cards;
55 long long scanned_objects;
56 long long remarked_cards;
57
58 static long long los_marked_cards;
59 static long long large_objects;
60 static long long bloby_objects;
61 static long long los_array_cards;
62 static long long los_array_remsets;
63
64 #endif
65 static long long major_card_scan_time;
66 static long long los_card_scan_time;
67
68 static long long last_major_scan_time;
69 static long long last_los_scan_time;
70
71 static void sgen_card_tables_collect_stats (gboolean begin);
72
73
74 /*WARNING: This function returns the number of cards regardless of overflow in case of overlapping cards.*/
75 static mword
76 cards_in_range (mword address, mword size)
77 {
78         mword end = address + MAX (1, size) - 1;
79         return (end >> CARD_BITS) - (address >> CARD_BITS) + 1;
80 }
81
82 static void
83 sgen_card_table_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* value)
84 {
85         *(void**)field_ptr = value;
86         if (need_mod_union || sgen_ptr_in_nursery (value))
87                 sgen_card_table_mark_address ((mword)field_ptr);
88         sgen_dummy_use (value);
89 }
90
91 static void
92 sgen_card_table_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* value)
93 {
94         *(void**)slot_ptr = value;
95         if (need_mod_union || sgen_ptr_in_nursery (value))
96                 sgen_card_table_mark_address ((mword)slot_ptr);
97         sgen_dummy_use (value); 
98 }
99
100 static void
101 sgen_card_table_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
102 {
103         gpointer *dest = dest_ptr;
104         gpointer *src = src_ptr;
105
106         /*overlapping that required backward copying*/
107         if (src < dest && (src + count) > dest) {
108                 gpointer *start = dest;
109                 dest += count - 1;
110                 src += count - 1;
111
112                 for (; dest >= start; --src, --dest) {
113                         gpointer value = *src;
114                         *dest = value;
115                         if (need_mod_union || sgen_ptr_in_nursery (value))
116                                 sgen_card_table_mark_address ((mword)dest);
117                         sgen_dummy_use (value);
118                 }
119         } else {
120                 gpointer *end = dest + count;
121                 for (; dest < end; ++src, ++dest) {
122                         gpointer value = *src;
123                         *dest = value;
124                         if (need_mod_union || sgen_ptr_in_nursery (value))
125                                 sgen_card_table_mark_address ((mword)dest);
126                         sgen_dummy_use (value);
127                 }
128         }       
129 }
130
131 static void
132 sgen_card_table_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass)
133 {
134         size_t element_size = mono_class_value_size (klass, NULL);
135         size_t size = count * element_size;
136
137 #ifdef DISABLE_CRITICAL_REGION
138         LOCK_GC;
139 #else
140         TLAB_ACCESS_INIT;
141         ENTER_CRITICAL_REGION;
142 #endif
143         mono_gc_memmove (dest, src, size);
144         sgen_card_table_mark_range ((mword)dest, size);
145 #ifdef DISABLE_CRITICAL_REGION
146         UNLOCK_GC;
147 #else
148         EXIT_CRITICAL_REGION;
149 #endif
150 }
151
152 static void
153 sgen_card_table_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
154 {
155         int size = mono_object_class (obj)->instance_size;
156
157 #ifdef DISABLE_CRITICAL_REGION
158         LOCK_GC;
159 #else
160         TLAB_ACCESS_INIT;
161         ENTER_CRITICAL_REGION;
162 #endif
163         mono_gc_memmove ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject),
164                         size - sizeof (MonoObject));
165         sgen_card_table_mark_range ((mword)obj, size);
166 #ifdef DISABLE_CRITICAL_REGION
167         UNLOCK_GC;
168 #else
169         EXIT_CRITICAL_REGION;
170 #endif  
171 }
172
173 static void
174 sgen_card_table_wbarrier_generic_nostore (gpointer ptr)
175 {
176         sgen_card_table_mark_address ((mword)ptr);      
177 }
178
179 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
180
181 guint8 *sgen_shadow_cardtable;
182
183 #define SGEN_SHADOW_CARDTABLE_END (sgen_shadow_cardtable + CARD_COUNT_IN_BYTES)
184 #define SGEN_CARDTABLE_END (sgen_cardtable + CARD_COUNT_IN_BYTES)
185
186 static gboolean
187 sgen_card_table_region_begin_scanning (mword start, mword end)
188 {
189         /*XXX this can be improved to work on words and have a single loop induction var */
190         while (start <= end) {
191                 if (sgen_card_table_card_begin_scanning (start))
192                         return TRUE;
193                 start += CARD_SIZE_IN_BYTES;
194         }
195         return FALSE;
196 }
197
198 #else
199
200 static gboolean
201 sgen_card_table_region_begin_scanning (mword start, mword size)
202 {
203         gboolean res = FALSE;
204         guint8 *card = sgen_card_table_get_card_address (start);
205         guint8 *end = card + cards_in_range (start, size);
206
207         /*XXX this can be improved to work on words and have a branchless body */
208         while (card != end) {
209                 if (*card++) {
210                         res = TRUE;
211                         break;
212                 }
213         }
214
215         memset (sgen_card_table_get_card_address (start), 0, size >> CARD_BITS);
216
217         return res;
218 }
219
220 #endif
221
222 /*FIXME this assumes that major blocks are multiple of 4K which is pretty reasonable */
223 gboolean
224 sgen_card_table_get_card_data (guint8 *data_dest, mword address, mword cards)
225 {
226         mword *start = (mword*)sgen_card_table_get_card_scan_address (address);
227         mword *dest = (mword*)data_dest;
228         mword *end = (mword*)(data_dest + cards);
229         mword mask = 0;
230
231         for (; dest < end; ++dest, ++start) {
232                 mword v = *start;
233                 *dest = v;
234                 mask |= v;
235
236 #ifndef SGEN_HAVE_OVERLAPPING_CARDS
237                 *start = 0;
238 #endif
239         }
240
241         return mask;
242 }
243
244 void*
245 sgen_card_table_align_pointer (void *ptr)
246 {
247         return (void*)((mword)ptr & ~(CARD_SIZE_IN_BYTES - 1));
248 }
249
250 void
251 sgen_card_table_mark_range (mword address, mword size)
252 {
253         memset (sgen_card_table_get_card_address (address), 1, cards_in_range (address, size));
254 }
255
256 static gboolean
257 sgen_card_table_is_range_marked (guint8 *cards, mword address, mword size)
258 {
259         guint8 *end = cards + cards_in_range (address, size);
260
261         /*This is safe since this function is only called by code that only passes continuous card blocks*/
262         while (cards != end) {
263                 if (*cards++)
264                         return TRUE;
265         }
266         return FALSE;
267
268 }
269
270 static void
271 sgen_card_table_record_pointer (gpointer address)
272 {
273         *sgen_card_table_get_card_address ((mword)address) = 1;
274 }
275
276 static gboolean
277 sgen_card_table_find_address (char *addr)
278 {
279         return sgen_card_table_address_is_marked ((mword)addr);
280 }
281
282 static gboolean
283 sgen_card_table_find_address_with_cards (char *cards_start, guint8 *cards, char *addr)
284 {
285         cards_start = sgen_card_table_align_pointer (cards_start);
286         return cards [(addr - cards_start) >> CARD_BITS];
287 }
288
289 static void
290 update_mod_union (guint8 *dest, gboolean init, guint8 *start_card, guint8 *end_card)
291 {
292         size_t num_cards = end_card - start_card;
293         if (init) {
294                 memcpy (dest, start_card, num_cards);
295         } else {
296                 int i;
297                 for (i = 0; i < num_cards; ++i)
298                         dest [i] |= start_card [i];
299         }
300 }
301
302 static guint8*
303 alloc_mod_union (size_t num_cards)
304 {
305         return sgen_alloc_internal_dynamic (num_cards, INTERNAL_MEM_CARDTABLE_MOD_UNION, TRUE);
306 }
307
308 guint8*
309 sgen_card_table_update_mod_union (guint8 *dest, char *obj, mword obj_size, size_t *out_num_cards)
310 {
311         guint8 *result = dest;
312         guint8 *start_card = sgen_card_table_get_card_address ((mword)obj);
313         guint8 *end_card = sgen_card_table_get_card_address ((mword)obj + obj_size - 1) + 1;
314         gboolean init = dest == NULL;
315         size_t num_cards;
316
317 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
318         if (end_card < start_card) {
319                 guint8 *edge_card = sgen_cardtable + CARD_COUNT_IN_BYTES;
320                 size_t num_cards_to_edge = edge_card - start_card;
321
322                 num_cards = (end_card + CARD_COUNT_IN_BYTES) - start_card;
323                 if (init) {
324                         result = dest = alloc_mod_union (num_cards);
325                         //g_print ("%d cards for %d bytes: %p\n", num_cards, num_bytes, dest);
326                 }
327
328                 update_mod_union (dest, init, start_card, edge_card);
329
330                 SGEN_ASSERT (0, num_cards == (edge_card - start_card) + (end_card - sgen_cardtable), "wrong number of cards");
331
332                 dest += num_cards_to_edge;
333                 start_card = sgen_cardtable;
334         } else
335 #endif
336         {
337                 num_cards = end_card - start_card;
338                 if (init)
339                         result = dest = alloc_mod_union (num_cards);
340         }
341
342         update_mod_union (dest, init, start_card, end_card);
343
344         if (out_num_cards)
345                 *out_num_cards = num_cards;
346
347         return result;
348 }
349
350 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
351
352 static void
353 move_cards_to_shadow_table (mword start, mword size)
354 {
355         guint8 *from = sgen_card_table_get_card_address (start);
356         guint8 *to = sgen_card_table_get_shadow_card_address (start);
357         size_t bytes = cards_in_range (start, size);
358
359         if (to + bytes > SGEN_SHADOW_CARDTABLE_END) {
360                 size_t first_chunk = SGEN_SHADOW_CARDTABLE_END - to;
361                 size_t second_chunk = MIN (CARD_COUNT_IN_BYTES, bytes) - first_chunk;
362
363                 memcpy (to, from, first_chunk);
364                 memcpy (sgen_shadow_cardtable, sgen_cardtable, second_chunk);
365         } else {
366                 memcpy (to, from, bytes);
367         }
368 }
369
370 static void
371 clear_cards (mword start, mword size)
372 {
373         guint8 *addr = sgen_card_table_get_card_address (start);
374         size_t bytes = cards_in_range (start, size);
375
376         if (addr + bytes > SGEN_CARDTABLE_END) {
377                 size_t first_chunk = SGEN_CARDTABLE_END - addr;
378
379                 memset (addr, 0, first_chunk);
380                 memset (sgen_cardtable, 0, bytes - first_chunk);
381         } else {
382                 memset (addr, 0, bytes);
383         }
384 }
385
386
387 #else
388
389 static void
390 clear_cards (mword start, mword size)
391 {
392         memset (sgen_card_table_get_card_address (start), 0, cards_in_range (start, size));
393 }
394
395
396 #endif
397
398 static void
399 sgen_card_table_prepare_for_major_collection (void)
400 {
401         /*XXX we could do this in 2 ways. using mincore or iterating over all sections/los objects */
402         sgen_major_collector_iterate_live_block_ranges (clear_cards);
403         sgen_los_iterate_live_block_ranges (clear_cards);
404 }
405
406 static void
407 sgen_card_table_finish_minor_collection (void)
408 {
409         sgen_card_tables_collect_stats (FALSE);
410 }
411
412 static void
413 sgen_card_table_finish_scan_remsets (void *start_nursery, void *end_nursery, SgenGrayQueue *queue)
414 {
415         SGEN_TV_DECLARE (atv);
416         SGEN_TV_DECLARE (btv);
417
418         sgen_card_tables_collect_stats (TRUE);
419
420 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
421         /*FIXME we should have a bit on each block/los object telling if the object have marked cards.*/
422         /*First we copy*/
423         sgen_major_collector_iterate_live_block_ranges (move_cards_to_shadow_table);
424         sgen_los_iterate_live_block_ranges (move_cards_to_shadow_table);
425
426         /*Then we clear*/
427         sgen_card_table_prepare_for_major_collection ();
428 #endif
429         SGEN_TV_GETTIME (atv);
430         sgen_major_collector_scan_card_table (queue);
431         SGEN_TV_GETTIME (btv);
432         last_major_scan_time = SGEN_TV_ELAPSED (atv, btv); 
433         major_card_scan_time += last_major_scan_time;
434         sgen_los_scan_card_table (FALSE, queue);
435         SGEN_TV_GETTIME (atv);
436         last_los_scan_time = SGEN_TV_ELAPSED (btv, atv);
437         los_card_scan_time += last_los_scan_time;
438 }
439
440 guint8*
441 mono_gc_get_card_table (int *shift_bits, gpointer *mask)
442 {
443         if (!sgen_cardtable)
444                 return NULL;
445
446         *shift_bits = CARD_BITS;
447 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
448         *mask = (gpointer)CARD_MASK;
449 #else
450         *mask = NULL;
451 #endif
452
453         return sgen_cardtable;
454 }
455
456 gboolean
457 mono_gc_card_table_nursery_check (void)
458 {
459         return !major_collector.is_concurrent;
460 }
461
462 #if 0
463 static void
464 collect_faulted_cards (void)
465 {
466 #define CARD_PAGES (CARD_COUNT_IN_BYTES / 4096)
467         int i, count = 0;
468         unsigned char faulted [CARD_PAGES] = { 0 };
469         mincore (sgen_cardtable, CARD_COUNT_IN_BYTES, faulted);
470
471         for (i = 0; i < CARD_PAGES; ++i) {
472                 if (faulted [i])
473                         ++count;
474         }
475
476         printf ("TOTAL card pages %d faulted %d\n", CARD_PAGES, count);
477 }
478
479 void
480 sgen_card_table_dump_obj_card (char *object, size_t size, void *dummy)
481 {
482         guint8 *start = sgen_card_table_get_card_scan_address (object);
483         guint8 *end = start + cards_in_range (object, size);
484         int cnt = 0;
485         printf ("--obj %p %d cards [%p %p]--", object, size, start, end);
486         for (; start < end; ++start) {
487                 if (cnt == 0)
488                         printf ("\n\t[%p] ", start);
489                 printf ("%x ", *start);
490                 ++cnt;
491                 if (cnt == 8)
492                         cnt = 0;
493         }
494         printf ("\n");
495 }
496 #endif
497
498 #define MWORD_MASK (sizeof (mword) - 1)
499
500 static inline int
501 find_card_offset (mword card)
502 {
503 /*XXX Use assembly as this generates some pretty bad code */
504 #if defined(__i386__) && defined(__GNUC__)
505         return  (__builtin_ffs (card) - 1) / 8;
506 #elif defined(__x86_64__) && defined(__GNUC__)
507         return (__builtin_ffsll (card) - 1) / 8;
508 #elif defined(__s390x__)
509         return (__builtin_ffsll (GUINT64_TO_LE(card)) - 1) / 8;
510 #else
511         int i;
512         guint8 *ptr = (guint8 *) &card;
513         for (i = 0; i < sizeof (mword); ++i) {
514                 if (ptr[i])
515                         return i;
516         }
517         return 0;
518 #endif
519 }
520
521 static guint8*
522 find_next_card (guint8 *card_data, guint8 *end)
523 {
524         mword *cards, *cards_end;
525         mword card;
526
527         while ((((mword)card_data) & MWORD_MASK) && card_data < end) {
528                 if (*card_data)
529                         return card_data;
530                 ++card_data;
531         }
532
533         if (card_data == end)
534                 return end;
535
536         cards = (mword*)card_data;
537         cards_end = (mword*)((mword)end & ~MWORD_MASK);
538         while (cards < cards_end) {
539                 card = *cards;
540                 if (card)
541                         return (guint8*)cards + find_card_offset (card);
542                 ++cards;
543         }
544
545         card_data = (guint8*)cards_end;
546         while (card_data < end) {
547                 if (*card_data)
548                         return card_data;
549                 ++card_data;
550         }
551
552         return end;
553 }
554
555 void
556 sgen_cardtable_scan_object (char *obj, mword block_obj_size, guint8 *cards, gboolean mod_union, SgenGrayQueue *queue)
557 {
558         MonoVTable *vt = (MonoVTable*)SGEN_LOAD_VTABLE (obj);
559         MonoClass *klass = vt->klass;
560
561         HEAVY_STAT (++large_objects);
562
563         if (!SGEN_VTABLE_HAS_REFERENCES (vt)) {
564                 sgen_object_layout_scanned_bitmap (0);
565                 return;
566         }
567
568         if (vt->rank) {
569                 guint8 *card_data, *card_base;
570                 guint8 *card_data_end;
571                 char *obj_start = sgen_card_table_align_pointer (obj);
572                 mword obj_size = sgen_par_object_get_size (vt, (MonoObject*)obj);
573                 char *obj_end = obj + obj_size;
574                 size_t card_count;
575                 int extra_idx = 0;
576
577                 MonoArray *arr = (MonoArray*)obj;
578                 mword desc = (mword)klass->element_class->gc_descr;
579                 int elem_size = mono_array_element_size (klass);
580
581 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
582                 guint8 *overflow_scan_end = NULL;
583 #endif
584
585 #ifdef SGEN_OBJECT_LAYOUT_STATISTICS
586                 if (klass->element_class->valuetype)
587                         sgen_object_layout_scanned_vtype_array ();
588                 else
589                         sgen_object_layout_scanned_ref_array ();
590 #endif
591
592                 if (cards)
593                         card_data = cards;
594                 else
595                         card_data = sgen_card_table_get_card_scan_address ((mword)obj);
596
597                 card_base = card_data;
598                 card_count = cards_in_range ((mword)obj, obj_size);
599                 card_data_end = card_data + card_count;
600
601
602 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
603                 /*Check for overflow and if so, setup to scan in two steps*/
604                 if (!cards && card_data_end >= SGEN_SHADOW_CARDTABLE_END) {
605                         overflow_scan_end = sgen_shadow_cardtable + (card_data_end - SGEN_SHADOW_CARDTABLE_END);
606                         card_data_end = SGEN_SHADOW_CARDTABLE_END;
607                 }
608
609 LOOP_HEAD:
610 #endif
611
612                 card_data = find_next_card (card_data, card_data_end);
613                 for (; card_data < card_data_end; card_data = find_next_card (card_data + 1, card_data_end)) {
614                         int index;
615                         int idx = (card_data - card_base) + extra_idx;
616                         char *start = (char*)(obj_start + idx * CARD_SIZE_IN_BYTES);
617                         char *card_end = start + CARD_SIZE_IN_BYTES;
618                         char *first_elem, *elem;
619
620                         HEAVY_STAT (++los_marked_cards);
621
622                         if (!cards)
623                                 sgen_card_table_prepare_card_for_scanning (card_data);
624
625                         card_end = MIN (card_end, obj_end);
626
627                         if (start <= (char*)arr->vector)
628                                 index = 0;
629                         else
630                                 index = ARRAY_OBJ_INDEX (start, obj, elem_size);
631
632                         elem = first_elem = (char*)mono_array_addr_with_size ((MonoArray*)obj, elem_size, index);
633                         if (klass->element_class->valuetype) {
634                                 ScanVTypeFunc scan_vtype_func = sgen_get_current_object_ops ()->scan_vtype;
635
636                                 for (; elem < card_end; elem += elem_size)
637                                         scan_vtype_func (elem, desc, queue BINARY_PROTOCOL_ARG (elem_size));
638                         } else {
639                                 CopyOrMarkObjectFunc copy_func = sgen_get_current_object_ops ()->copy_or_mark_object;
640
641                                 HEAVY_STAT (++los_array_cards);
642                                 for (; elem < card_end; elem += SIZEOF_VOID_P) {
643                                         gpointer new, old = *(gpointer*)elem;
644                                         if ((mod_union && old) || G_UNLIKELY (sgen_ptr_in_nursery (old))) {
645                                                 HEAVY_STAT (++los_array_remsets);
646                                                 copy_func ((void**)elem, queue);
647                                                 new = *(gpointer*)elem;
648                                                 if (G_UNLIKELY (sgen_ptr_in_nursery (new)))
649                                                         sgen_add_to_global_remset (elem, new);
650                                         }
651                                 }
652                         }
653
654                         binary_protocol_card_scan (first_elem, elem - first_elem);
655                 }
656
657 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
658                 if (overflow_scan_end) {
659                         extra_idx = card_data - card_base;
660                         card_base = card_data = sgen_shadow_cardtable;
661                         card_data_end = overflow_scan_end;
662                         overflow_scan_end = NULL;
663                         goto LOOP_HEAD;
664                 }
665 #endif
666
667         } else {
668                 HEAVY_STAT (++bloby_objects);
669                 if (cards) {
670                         if (sgen_card_table_is_range_marked (cards, (mword)obj, block_obj_size))
671                                 sgen_get_current_object_ops ()->scan_object (obj, queue);
672                 } else if (sgen_card_table_region_begin_scanning ((mword)obj, block_obj_size)) {
673                         sgen_get_current_object_ops ()->scan_object (obj, queue);
674                 }
675
676                 binary_protocol_card_scan (obj, sgen_safe_object_get_size ((MonoObject*)obj));
677         }
678 }
679
680 #ifdef CARDTABLE_STATS
681
682 typedef struct {
683         int total, marked, remarked, gc_marked; 
684 } card_stats;
685
686 static card_stats major_stats, los_stats;
687 static card_stats *cur_stats;
688
689 static void
690 count_marked_cards (mword start, mword size)
691 {
692         mword end = start + size;
693         while (start <= end) {
694                 guint8 card = *sgen_card_table_get_card_address (start);
695                 ++cur_stats->total;
696                 if (card)
697                         ++cur_stats->marked;
698                 if (card == 2)
699                         ++cur_stats->gc_marked;
700                 start += CARD_SIZE_IN_BYTES;
701         }
702 }
703
704 static void
705 count_remarked_cards (mword start, mword size)
706 {
707         mword end = start + size;
708         while (start <= end) {
709                 if (sgen_card_table_address_is_marked (start)) {
710                         ++cur_stats->remarked;
711                         *sgen_card_table_get_card_address (start) = 2;
712                 }
713                 start += CARD_SIZE_IN_BYTES;
714         }
715 }
716
717 #endif
718
719 static void
720 sgen_card_tables_collect_stats (gboolean begin)
721 {
722 #ifdef CARDTABLE_STATS
723         if (begin) {
724                 memset (&major_stats, 0, sizeof (card_stats));
725                 memset (&los_stats, 0, sizeof (card_stats));
726                 cur_stats = &major_stats;
727                 sgen_major_collector_iterate_live_block_ranges (count_marked_cards);
728                 cur_stats = &los_stats;
729                 sgen_los_iterate_live_block_ranges (count_marked_cards);
730         } else {
731                 cur_stats = &major_stats;
732                 sgen_major_collector_iterate_live_block_ranges (count_remarked_cards);
733                 cur_stats = &los_stats;
734                 sgen_los_iterate_live_block_ranges (count_remarked_cards);
735                 printf ("cards major (t %d m %d g %d r %d)  los (t %d m %d g %d r %d) major_scan %.2fms los_scan %.2fms\n", 
736                         major_stats.total, major_stats.marked, major_stats.gc_marked, major_stats.remarked,
737                         los_stats.total, los_stats.marked, los_stats.gc_marked, los_stats.remarked,
738                         last_major_scan_time / 1000.0, last_los_scan_time / 1000.0);
739         }
740 #endif
741 }
742
743 void
744 sgen_card_table_init (SgenRemeberedSet *remset)
745 {
746         sgen_cardtable = sgen_alloc_os_memory (CARD_COUNT_IN_BYTES, SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE, "card table");
747
748 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
749         sgen_shadow_cardtable = sgen_alloc_os_memory (CARD_COUNT_IN_BYTES, SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE, "shadow card table");
750 #endif
751
752 #ifdef HEAVY_STATISTICS
753         mono_counters_register ("marked cards", MONO_COUNTER_GC | MONO_COUNTER_LONG, &marked_cards);
754         mono_counters_register ("scanned cards", MONO_COUNTER_GC | MONO_COUNTER_LONG, &scanned_cards);
755         mono_counters_register ("remarked cards", MONO_COUNTER_GC | MONO_COUNTER_LONG, &remarked_cards);
756
757         mono_counters_register ("los marked cards", MONO_COUNTER_GC | MONO_COUNTER_LONG, &los_marked_cards);
758         mono_counters_register ("los array cards scanned ", MONO_COUNTER_GC | MONO_COUNTER_LONG, &los_array_cards);
759         mono_counters_register ("los array remsets", MONO_COUNTER_GC | MONO_COUNTER_LONG, &los_array_remsets);
760         mono_counters_register ("cardtable scanned objects", MONO_COUNTER_GC | MONO_COUNTER_LONG, &scanned_objects);
761         mono_counters_register ("cardtable large objects", MONO_COUNTER_GC | MONO_COUNTER_LONG, &large_objects);
762         mono_counters_register ("cardtable bloby objects", MONO_COUNTER_GC | MONO_COUNTER_LONG, &bloby_objects);
763 #endif
764         mono_counters_register ("cardtable major scan time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &major_card_scan_time);
765         mono_counters_register ("cardtable los scan time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &los_card_scan_time);
766
767
768         remset->wbarrier_set_field = sgen_card_table_wbarrier_set_field;
769         remset->wbarrier_set_arrayref = sgen_card_table_wbarrier_set_arrayref;
770         remset->wbarrier_arrayref_copy = sgen_card_table_wbarrier_arrayref_copy;
771         remset->wbarrier_value_copy = sgen_card_table_wbarrier_value_copy;
772         remset->wbarrier_object_copy = sgen_card_table_wbarrier_object_copy;
773         remset->wbarrier_generic_nostore = sgen_card_table_wbarrier_generic_nostore;
774         remset->record_pointer = sgen_card_table_record_pointer;
775
776         remset->finish_scan_remsets = sgen_card_table_finish_scan_remsets;
777
778         remset->finish_minor_collection = sgen_card_table_finish_minor_collection;
779         remset->prepare_for_major_collection = sgen_card_table_prepare_for_major_collection;
780
781         remset->find_address = sgen_card_table_find_address;
782         remset->find_address_with_cards = sgen_card_table_find_address_with_cards;
783
784         need_mod_union = sgen_get_major_collector ()->is_concurrent;
785 }
786
787 #endif /*HAVE_SGEN_GC*/