2 * sgen-ssb.c: Remembered sets
5 * Rodrigo Kumpera (rkumpera@novell.com)
7 * SGen is licensed under the terms of the MIT X11 license
9 * Copyright 2001-2003 Ximian, Inc
10 * Copyright 2003-2010 Novell, Inc.
11 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
13 * Permission is hereby granted, free of charge, to any person obtaining
14 * a copy of this software and associated documentation files (the
15 * "Software"), to deal in the Software without restriction, including
16 * without limitation the rights to use, copy, modify, merge, publish,
17 * distribute, sublicense, and/or sell copies of the Software, and to
18 * permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
21 * The above copyright notice and this permission notice shall be
22 * included in all copies or substantial portions of the Software.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 #include "metadata/sgen-gc.h"
37 #include "metadata/sgen-ssb.h"
38 #include "metadata/sgen-protocol.h"
39 #include "utils/mono-counters.h"
41 #ifndef DISABLE_SGEN_REMSET
43 /*A two slots cache for recently inserted remsets */
44 static gpointer global_remset_cache [2];
46 static LOCK_DECLARE (global_remset_mutex);
48 #define LOCK_GLOBAL_REMSET mono_mutex_lock (&global_remset_mutex)
49 #define UNLOCK_GLOBAL_REMSET mono_mutex_unlock (&global_remset_mutex)
52 static __thread RememberedSet *remembered_set MONO_TLS_FAST;
54 static MonoNativeTlsKey remembered_set_key;
55 static RememberedSet *global_remset;
56 static RememberedSet *freed_thread_remsets;
57 static GenericStoreRememberedSet *generic_store_remsets = NULL;
59 #ifdef HEAVY_STATISTICS
60 static int stat_wbarrier_generic_store_remset = 0;
62 static long long stat_store_remsets = 0;
63 static long long stat_store_remsets_unique = 0;
64 static long long stat_saved_remsets_1 = 0;
65 static long long stat_saved_remsets_2 = 0;
66 static long long stat_local_remsets_processed = 0;
67 static long long stat_global_remsets_added = 0;
68 static long long stat_global_remsets_readded = 0;
69 static long long stat_global_remsets_processed = 0;
70 static long long stat_global_remsets_discarded = 0;
74 static gboolean global_remset_location_was_not_added (gpointer ptr);
78 clear_thread_store_remset_buffer (SgenThreadInfo *info)
80 *info->store_remset_buffer_index_addr = 0;
81 /* See the comment at the end of sgen_thread_unregister() */
82 if (*info->store_remset_buffer_addr)
83 memset (*info->store_remset_buffer_addr, 0, sizeof (gpointer) * STORE_REMSET_BUFFER_SIZE);
87 remset_byte_size (RememberedSet *remset)
89 return sizeof (RememberedSet) + (remset->end_set - remset->data) * sizeof (gpointer);
93 add_generic_store_remset_from_buffer (gpointer *buffer)
95 GenericStoreRememberedSet *remset = sgen_alloc_internal (INTERNAL_MEM_STORE_REMSET);
96 memcpy (remset->data, buffer + 1, sizeof (gpointer) * (STORE_REMSET_BUFFER_SIZE - 1));
97 remset->next = generic_store_remsets;
98 generic_store_remsets = remset;
102 evacuate_remset_buffer (void)
107 buffer = STORE_REMSET_BUFFER;
109 add_generic_store_remset_from_buffer (buffer);
110 memset (buffer, 0, sizeof (gpointer) * STORE_REMSET_BUFFER_SIZE);
112 STORE_REMSET_BUFFER_INDEX = 0;
115 /* FIXME: later choose a size that takes into account the RememberedSet struct
116 * and doesn't waste any alloc paddin space.
118 static RememberedSet*
119 sgen_alloc_remset (int size, gpointer id, gboolean global)
121 RememberedSet* res = sgen_alloc_internal_dynamic (sizeof (RememberedSet) + (size * sizeof (gpointer)), INTERNAL_MEM_REMSET, TRUE);
122 res->store_next = res->data;
123 res->end_set = res->data + size;
125 SGEN_LOG (4, "Allocated%s remset size %d at %p for %p", global ? " global" : "", size, res->data, id);
132 sgen_ssb_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* value)
139 if (rs->store_next < rs->end_set) {
140 *(rs->store_next++) = (mword)field_ptr;
141 *(void**)field_ptr = value;
145 rs = sgen_alloc_remset (rs->end_set - rs->data, (void*)1, FALSE);
146 rs->next = REMEMBERED_SET;
148 #ifdef HAVE_KW_THREAD
149 mono_thread_info_current ()->remset = rs;
151 *(rs->store_next++) = (mword)field_ptr;
152 *(void**)field_ptr = value;
157 sgen_ssb_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* value)
164 if (rs->store_next < rs->end_set) {
165 *(rs->store_next++) = (mword)slot_ptr;
166 *(void**)slot_ptr = value;
170 rs = sgen_alloc_remset (rs->end_set - rs->data, (void*)1, FALSE);
171 rs->next = REMEMBERED_SET;
173 #ifdef HAVE_KW_THREAD
174 mono_thread_info_current ()->remset = rs;
176 *(rs->store_next++) = (mword)slot_ptr;
177 *(void**)slot_ptr = value;
182 sgen_ssb_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
187 mono_gc_memmove (dest_ptr, src_ptr, count * sizeof (gpointer));
190 SGEN_LOG (8, "Adding remset at %p, %d", dest_ptr, count);
191 if (rs->store_next + 1 < rs->end_set) {
192 *(rs->store_next++) = (mword)dest_ptr | REMSET_RANGE;
193 *(rs->store_next++) = count;
197 rs = sgen_alloc_remset (rs->end_set - rs->data, (void*)1, FALSE);
198 rs->next = REMEMBERED_SET;
200 #ifdef HAVE_KW_THREAD
201 mono_thread_info_current ()->remset = rs;
203 *(rs->store_next++) = (mword)dest_ptr | REMSET_RANGE;
204 *(rs->store_next++) = count;
210 sgen_ssb_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass)
213 size_t element_size = mono_class_value_size (klass, NULL);
214 size_t size = count * element_size;
217 g_assert (klass->gc_descr_inited);
220 mono_gc_memmove (dest, src, size);
223 if (rs->store_next + 4 < rs->end_set) {
224 *(rs->store_next++) = (mword)dest | REMSET_VTYPE;
225 *(rs->store_next++) = (mword)klass->gc_descr;
226 *(rs->store_next++) = (mword)count;
227 *(rs->store_next++) = (mword)element_size;
231 rs = sgen_alloc_remset (rs->end_set - rs->data, (void*)1, FALSE);
232 rs->next = REMEMBERED_SET;
234 #ifdef HAVE_KW_THREAD
235 mono_thread_info_current ()->remset = rs;
237 *(rs->store_next++) = (mword)dest | REMSET_VTYPE;
238 *(rs->store_next++) = (mword)klass->gc_descr;
239 *(rs->store_next++) = (mword)count;
240 *(rs->store_next++) = (mword)element_size;
245 sgen_ssb_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
251 size = mono_object_class (obj)->instance_size;
254 SGEN_LOG (6, "Adding object remset for %p", obj);
257 /* do not copy the sync state */
258 mono_gc_memmove ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject),
259 size - sizeof (MonoObject));
261 if (rs->store_next < rs->end_set) {
262 *(rs->store_next++) = (mword)obj | REMSET_OBJECT;
266 rs = sgen_alloc_remset (rs->end_set - rs->data, (void*)1, FALSE);
267 rs->next = REMEMBERED_SET;
270 #ifdef HAVE_KW_THREAD
271 mono_thread_info_current ()->remset = rs;
273 *(rs->store_next++) = (mword)obj | REMSET_OBJECT;
278 sgen_ssb_wbarrier_generic_nostore (gpointer ptr)
286 buffer = STORE_REMSET_BUFFER;
287 index = STORE_REMSET_BUFFER_INDEX;
288 /* This simple optimization eliminates a sizable portion of
289 entries. Comparing it to the last but one entry as well
290 doesn't eliminate significantly more entries. */
291 if (buffer [index] == ptr) {
296 HEAVY_STAT (++stat_wbarrier_generic_store_remset);
299 if (index >= STORE_REMSET_BUFFER_SIZE) {
300 evacuate_remset_buffer ();
301 index = STORE_REMSET_BUFFER_INDEX;
302 g_assert (index == 0);
305 buffer [index] = ptr;
306 STORE_REMSET_BUFFER_INDEX = index;
312 #ifdef HEAVY_STATISTICS
314 collect_store_remsets (RememberedSet *remset, mword *bumper)
316 mword *p = remset->data;
321 while (p < remset->store_next) {
322 switch ((*p) & REMSET_TYPE_MASK) {
323 case REMSET_LOCATION:
326 ++stat_saved_remsets_1;
328 if (*p == last1 || *p == last2) {
329 ++stat_saved_remsets_2;
346 g_assert_not_reached ();
356 RememberedSet *remset;
358 SgenThreadInfo *info;
359 mword *addresses, *bumper, *p, *r;
361 FOREACH_THREAD (info) {
362 for (remset = info->remset; remset; remset = remset->next)
363 size += remset->store_next - remset->data;
365 for (remset = freed_thread_remsets; remset; remset = remset->next)
366 size += remset->store_next - remset->data;
367 for (remset = global_remset; remset; remset = remset->next)
368 size += remset->store_next - remset->data;
370 bumper = addresses = sgen_alloc_internal_dynamic (sizeof (mword) * size, INTERNAL_MEM_STATISTICS, TRUE);
372 FOREACH_THREAD (info) {
373 for (remset = info->remset; remset; remset = remset->next)
374 bumper = collect_store_remsets (remset, bumper);
376 for (remset = global_remset; remset; remset = remset->next)
377 bumper = collect_store_remsets (remset, bumper);
378 for (remset = freed_thread_remsets; remset; remset = remset->next)
379 bumper = collect_store_remsets (remset, bumper);
381 g_assert (bumper <= addresses + size);
383 stat_store_remsets += bumper - addresses;
385 sgen_sort_addresses ((void**)addresses, bumper - addresses);
394 stat_store_remsets_unique += p - addresses;
396 sgen_free_internal_dynamic (addresses, sizeof (mword) * size, INTERNAL_MEM_STATISTICS);
402 handle_remset (mword *p, void *start_nursery, void *end_nursery, gboolean global, SgenGrayQueue *queue)
409 HEAVY_STAT (++stat_global_remsets_processed);
411 HEAVY_STAT (++stat_local_remsets_processed);
413 /* FIXME: exclude stack locations */
414 switch ((*p) & REMSET_TYPE_MASK) {
415 case REMSET_LOCATION:
417 //__builtin_prefetch (ptr);
418 if (((void*)ptr < start_nursery || (void*)ptr >= end_nursery)) {
421 sgen_get_current_object_ops ()->copy_or_mark_object (ptr, queue);
422 SGEN_LOG (9, "Overwrote remset at %p with %p", ptr, *ptr);
424 binary_protocol_ptr_update (ptr, old, *ptr, (gpointer)SGEN_LOAD_VTABLE (*ptr), sgen_safe_object_get_size (*ptr));
425 if (!global && *ptr >= start_nursery && *ptr < end_nursery) {
427 * If the object is pinned, each reference to it from nonpinned objects
428 * becomes part of the global remset, which can grow very large.
430 SGEN_LOG (9, "Add to global remset because of pinning %p (%p %s)", ptr, *ptr, sgen_safe_name (*ptr));
431 sgen_add_to_global_remset (ptr);
434 SGEN_LOG (9, "Skipping remset at %p holding %p", ptr, *ptr);
438 CopyOrMarkObjectFunc copy_func = sgen_get_current_object_ops ()->copy_or_mark_object;
440 ptr = (void**)(*p & ~REMSET_TYPE_MASK);
441 if (((void*)ptr >= start_nursery && (void*)ptr < end_nursery))
444 while (count-- > 0) {
445 copy_func (ptr, queue);
446 SGEN_LOG (9, "Overwrote remset at %p with %p (count: %d)", ptr, *ptr, (int)count);
447 if (!global && *ptr >= start_nursery && *ptr < end_nursery)
448 sgen_add_to_global_remset (ptr);
454 ptr = (void**)(*p & ~REMSET_TYPE_MASK);
455 if (((void*)ptr >= start_nursery && (void*)ptr < end_nursery))
457 sgen_get_current_object_ops ()->scan_object ((char*)ptr, queue);
462 ptr = (void**)(*p & ~REMSET_TYPE_MASK);
463 if (((void*)ptr >= start_nursery && (void*)ptr < end_nursery))
468 while (count-- > 0) {
469 sgen_get_current_object_ops ()->scan_vtype ((char*)ptr, desc, queue);
470 ptr = (void**)((char*)ptr + skip_size);
475 g_assert_not_reached ();
481 sgen_ssb_begin_scan_remsets (void *start_nursery, void *end_nursery, SgenGrayQueue *queue)
483 RememberedSet *remset;
484 mword *p, *next_p, *store_pos;
487 for (remset = global_remset; remset; remset = remset->next) {
488 SGEN_LOG (4, "Scanning global remset range: %p-%p, size: %td", remset->data, remset->store_next, remset->store_next - remset->data);
489 store_pos = remset->data;
490 for (p = remset->data; p < remset->store_next; p = next_p) {
491 void **ptr = (void**)p [0];
493 /*Ignore previously processed remset.*/
494 if (!global_remset_location_was_not_added (ptr)) {
499 next_p = handle_remset (p, start_nursery, end_nursery, TRUE, queue);
502 * Clear global remsets of locations which no longer point to the
503 * nursery. Otherwise, they could grow indefinitely between major
506 * Since all global remsets are location remsets, we don't need to unmask the pointer.
508 if (sgen_ptr_in_nursery (*ptr)) {
509 *store_pos ++ = p [0];
510 HEAVY_STAT (++stat_global_remsets_readded);
514 /* Truncate the remset */
515 remset->store_next = store_pos;
520 sgen_ssb_finish_scan_remsets (void *start_nursery, void *end_nursery, SgenGrayQueue *queue)
523 SgenThreadInfo *info;
524 RememberedSet *remset;
525 GenericStoreRememberedSet *store_remset;
528 #ifdef HEAVY_STATISTICS
532 /* the generic store ones */
533 store_remset = generic_store_remsets;
534 while (store_remset) {
535 GenericStoreRememberedSet *next = store_remset->next;
537 for (i = 0; i < STORE_REMSET_BUFFER_SIZE - 1; ++i) {
538 gpointer addr = store_remset->data [i];
540 handle_remset ((mword*)&addr, start_nursery, end_nursery, FALSE, queue);
543 sgen_free_internal (store_remset, INTERNAL_MEM_STORE_REMSET);
547 generic_store_remsets = NULL;
549 /* the per-thread ones */
550 FOREACH_THREAD (info) {
553 for (remset = info->remset; remset; remset = next) {
554 SGEN_LOG (4, "Scanning remset for thread %p, range: %p-%p, size: %td", info, remset->data, remset->store_next, remset->store_next - remset->data);
555 for (p = remset->data; p < remset->store_next;)
556 p = handle_remset (p, start_nursery, end_nursery, FALSE, queue);
557 remset->store_next = remset->data;
560 if (remset != info->remset) {
561 SGEN_LOG (4, "Freed remset at %p", remset->data);
562 sgen_free_internal_dynamic (remset, remset_byte_size (remset), INTERNAL_MEM_REMSET);
565 for (j = 0; j < *info->store_remset_buffer_index_addr; ++j)
566 handle_remset ((mword*)*info->store_remset_buffer_addr + j + 1, start_nursery, end_nursery, FALSE, queue);
567 clear_thread_store_remset_buffer (info);
570 /* the freed thread ones */
571 while (freed_thread_remsets) {
573 remset = freed_thread_remsets;
574 SGEN_LOG (4, "Scanning remset for freed thread, range: %p-%p, size: %td", remset->data, remset->store_next, remset->store_next - remset->data);
575 for (p = remset->data; p < remset->store_next;)
576 p = handle_remset (p, start_nursery, end_nursery, FALSE, queue);
578 SGEN_LOG (4, "Freed remset at %p", remset->data);
579 sgen_free_internal_dynamic (remset, remset_byte_size (remset), INTERNAL_MEM_REMSET);
580 freed_thread_remsets = next;
586 sgen_ssb_cleanup_thread (SgenThreadInfo *p)
591 if (freed_thread_remsets) {
592 for (rset = p->remset; rset->next; rset = rset->next)
594 rset->next = freed_thread_remsets;
595 freed_thread_remsets = p->remset;
597 freed_thread_remsets = p->remset;
601 if (*p->store_remset_buffer_index_addr)
602 add_generic_store_remset_from_buffer (*p->store_remset_buffer_addr);
603 sgen_free_internal (*p->store_remset_buffer_addr, INTERNAL_MEM_STORE_REMSET);
606 * This is currently not strictly required, but we do it
607 * anyway in case we change thread unregistering:
609 * If the thread is removed from the thread list after
610 * unregistering (this is currently not the case), and a
611 * collection occurs, clear_remsets() would want to memset
612 * this buffer, which would either clobber memory or crash.
614 *p->store_remset_buffer_addr = NULL;
618 sgen_ssb_register_thread (SgenThreadInfo *info)
620 #ifndef HAVE_KW_THREAD
621 SgenThreadInfo *__thread_info__ = info;
624 info->remset = sgen_alloc_remset (DEFAULT_REMSET_SIZE, info, FALSE);
625 mono_native_tls_set_value (remembered_set_key, info->remset);
626 #ifdef HAVE_KW_THREAD
627 remembered_set = info->remset;
630 STORE_REMSET_BUFFER = sgen_alloc_internal (INTERNAL_MEM_STORE_REMSET);
631 STORE_REMSET_BUFFER_INDEX = 0;
634 #ifdef HAVE_KW_THREAD
636 sgen_ssb_fill_thread_info_for_suspend (SgenThreadInfo *info)
638 /* update the remset info in the thread data structure */
639 info->remset = remembered_set;
644 sgen_ssb_prepare_for_minor_collection (void)
646 memset (global_remset_cache, 0, sizeof (global_remset_cache));
650 * Clear the info in the remembered sets: we're doing a major collection, so
651 * the per-thread ones are not needed and the global ones will be reconstructed
655 sgen_ssb_prepare_for_major_collection (void)
657 SgenThreadInfo *info;
658 RememberedSet *remset, *next;
660 sgen_ssb_prepare_for_minor_collection ();
662 /* the global list */
663 for (remset = global_remset; remset; remset = next) {
664 remset->store_next = remset->data;
667 if (remset != global_remset) {
668 SGEN_LOG (4, "Freed remset at %p", remset->data);
669 sgen_free_internal_dynamic (remset, remset_byte_size (remset), INTERNAL_MEM_REMSET);
672 /* the generic store ones */
673 while (generic_store_remsets) {
674 GenericStoreRememberedSet *gs_next = generic_store_remsets->next;
675 sgen_free_internal (generic_store_remsets, INTERNAL_MEM_STORE_REMSET);
676 generic_store_remsets = gs_next;
678 /* the per-thread ones */
679 FOREACH_THREAD (info) {
680 for (remset = info->remset; remset; remset = next) {
681 remset->store_next = remset->data;
684 if (remset != info->remset) {
685 SGEN_LOG (3, "Freed remset at %p", remset->data);
686 sgen_free_internal_dynamic (remset, remset_byte_size (remset), INTERNAL_MEM_REMSET);
689 clear_thread_store_remset_buffer (info);
692 /* the freed thread ones */
693 while (freed_thread_remsets) {
694 next = freed_thread_remsets->next;
695 SGEN_LOG (4, "Freed remset at %p", freed_thread_remsets->data);
696 sgen_free_internal_dynamic (freed_thread_remsets, remset_byte_size (freed_thread_remsets), INTERNAL_MEM_REMSET);
697 freed_thread_remsets = next;
703 * Tries to check if a given remset location was already added to the global remset.
706 * A 2 entry, LRU cache of recently saw location remsets.
708 * It's hand-coded instead of done using loops to reduce the number of memory references on cache hit.
710 * Returns TRUE is the element was added..
713 global_remset_location_was_not_added (gpointer ptr)
716 gpointer first = global_remset_cache [0], second;
718 HEAVY_STAT (++stat_global_remsets_discarded);
722 second = global_remset_cache [1];
725 /*Move the second to the front*/
726 global_remset_cache [0] = second;
727 global_remset_cache [1] = first;
729 HEAVY_STAT (++stat_global_remsets_discarded);
733 global_remset_cache [0] = second;
734 global_remset_cache [1] = ptr;
739 sgen_ssb_record_pointer (gpointer ptr)
742 gboolean lock = sgen_collection_is_parallel ();
743 gpointer obj = *(gpointer*)ptr;
745 g_assert (!sgen_ptr_in_nursery (ptr) && sgen_ptr_in_nursery (obj));
750 if (!global_remset_location_was_not_added (ptr))
753 if (G_UNLIKELY (do_pin_stats))
754 sgen_pin_stats_register_global_remset (obj);
756 SGEN_LOG (8, "Adding global remset for %p", ptr);
757 binary_protocol_global_remset (ptr, *(gpointer*)ptr, (gpointer)SGEN_LOAD_VTABLE (obj));
759 HEAVY_STAT (++stat_global_remsets_added);
762 * FIXME: If an object remains pinned, we need to add it at every minor collection.
763 * To avoid uncontrolled growth of the global remset, only add each pointer once.
765 if (global_remset->store_next + 3 < global_remset->end_set) {
766 *(global_remset->store_next++) = (mword)ptr;
769 rs = sgen_alloc_remset (global_remset->end_set - global_remset->data, NULL, TRUE);
770 rs->next = global_remset;
772 *(global_remset->store_next++) = (mword)ptr;
775 int global_rs_size = 0;
777 for (rs = global_remset; rs; rs = rs->next) {
778 global_rs_size += rs->store_next - rs->data;
780 SGEN_LOG (4, "Global remset now has size %d", global_rs_size);
785 UNLOCK_GLOBAL_REMSET;
789 * ######################################################################
790 * ######## Debug support
791 * ######################################################################
795 find_in_remset_loc (mword *p, char *addr, gboolean *found)
801 switch ((*p) & REMSET_TYPE_MASK) {
802 case REMSET_LOCATION:
803 if (*p == (mword)addr)
807 ptr = (void**)(*p & ~REMSET_TYPE_MASK);
809 if ((void**)addr >= ptr && (void**)addr < ptr + count)
813 ptr = (void**)(*p & ~REMSET_TYPE_MASK);
814 count = sgen_safe_object_get_size ((MonoObject*)ptr);
815 count = SGEN_ALIGN_UP (count);
816 count /= sizeof (mword);
817 if ((void**)addr >= ptr && (void**)addr < ptr + count)
821 ptr = (void**)(*p & ~REMSET_TYPE_MASK);
826 /* The descriptor includes the size of MonoObject */
827 skip_size -= sizeof (MonoObject);
829 if ((void**)addr >= ptr && (void**)addr < ptr + (skip_size / sizeof (gpointer)))
834 g_assert_not_reached ();
839 * Return whenever ADDR occurs in the remembered sets
842 sgen_ssb_find_address (char *addr)
845 SgenThreadInfo *info;
846 RememberedSet *remset;
847 GenericStoreRememberedSet *store_remset;
849 gboolean found = FALSE;
852 for (remset = global_remset; remset; remset = remset->next) {
853 SGEN_LOG (4, "Scanning global remset range: %p-%p, size: %td", remset->data, remset->store_next, remset->store_next - remset->data);
854 for (p = remset->data; p < remset->store_next;) {
855 p = find_in_remset_loc (p, addr, &found);
861 /* the generic store ones */
862 for (store_remset = generic_store_remsets; store_remset; store_remset = store_remset->next) {
863 for (i = 0; i < STORE_REMSET_BUFFER_SIZE - 1; ++i) {
864 if (store_remset->data [i] == addr)
869 /* the per-thread ones */
870 FOREACH_THREAD (info) {
872 for (remset = info->remset; remset; remset = remset->next) {
873 SGEN_LOG (4, "Scanning remset for thread %p, range: %p-%p, size: %td", info, remset->data, remset->store_next, remset->store_next - remset->data);
874 for (p = remset->data; p < remset->store_next;) {
875 p = find_in_remset_loc (p, addr, &found);
880 for (j = 0; j < *info->store_remset_buffer_index_addr; ++j) {
881 if ((*info->store_remset_buffer_addr) [j + 1] == addr)
886 /* the freed thread ones */
887 for (remset = freed_thread_remsets; remset; remset = remset->next) {
888 SGEN_LOG (4, "Scanning remset for freed thread, range: %p-%p, size: %td", remset->data, remset->store_next, remset->store_next - remset->data);
889 for (p = remset->data; p < remset->store_next;) {
890 p = find_in_remset_loc (p, addr, &found);
900 sgen_ssb_init (SgenRemeberedSet *remset)
902 LOCK_INIT (global_remset_mutex);
904 global_remset = sgen_alloc_remset (1024, NULL, FALSE);
905 global_remset->next = NULL;
907 mono_native_tls_alloc (&remembered_set_key, NULL);
909 #ifdef HEAVY_STATISTICS
910 mono_counters_register ("WBarrier generic store stored", MONO_COUNTER_GC | MONO_COUNTER_INT, &stat_wbarrier_generic_store_remset);
912 mono_counters_register ("Store remsets", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_store_remsets);
913 mono_counters_register ("Unique store remsets", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_store_remsets_unique);
914 mono_counters_register ("Saved remsets 1", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_saved_remsets_1);
915 mono_counters_register ("Saved remsets 2", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_saved_remsets_2);
916 mono_counters_register ("Non-global remsets processed", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_local_remsets_processed);
917 mono_counters_register ("Global remsets added", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_global_remsets_added);
918 mono_counters_register ("Global remsets re-added", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_global_remsets_readded);
919 mono_counters_register ("Global remsets processed", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_global_remsets_processed);
920 mono_counters_register ("Global remsets discarded", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_global_remsets_discarded);
923 remset->wbarrier_set_field = sgen_ssb_wbarrier_set_field;
924 remset->wbarrier_set_arrayref = sgen_ssb_wbarrier_set_arrayref;
925 remset->wbarrier_arrayref_copy = sgen_ssb_wbarrier_arrayref_copy;
926 remset->wbarrier_value_copy = sgen_ssb_wbarrier_value_copy;
927 remset->wbarrier_object_copy = sgen_ssb_wbarrier_object_copy;
928 remset->wbarrier_generic_nostore = sgen_ssb_wbarrier_generic_nostore;
929 remset->record_pointer = sgen_ssb_record_pointer;
931 remset->begin_scan_remsets = sgen_ssb_begin_scan_remsets;
932 remset->finish_scan_remsets = sgen_ssb_finish_scan_remsets;
934 remset->register_thread = sgen_ssb_register_thread;
935 remset->cleanup_thread = sgen_ssb_cleanup_thread;
936 #ifdef HAVE_KW_THREAD
937 remset->fill_thread_info_for_suspend = sgen_ssb_fill_thread_info_for_suspend;
940 remset->prepare_for_minor_collection = sgen_ssb_prepare_for_minor_collection;
941 remset->prepare_for_major_collection = sgen_ssb_prepare_for_major_collection;
943 remset->find_address = sgen_ssb_find_address;
949 sgen_ssb_init (SgenRemeberedSet *remset)
951 fprintf (stderr, "Error: Mono was configured using --enable-minimal=sgen_wbarrier.\n");
955 #endif /* DISABLE_SGEN_REMSET */
957 #endif /* HAVE_SGEN_GC */