Merge pull request #261 from joncham/bug-null-interface-bitset
[mono.git] / mono / metadata / sgen-ssb.c
index 031ade85becd93302bc1d54ff4fe53d03b3a8931..65f0c6da55349dbeec632934bffbd5f31797c1c0 100644 (file)
@@ -47,12 +47,12 @@ static LOCK_DECLARE (global_remset_mutex);
 #define UNLOCK_GLOBAL_REMSET mono_mutex_unlock (&global_remset_mutex)
 
 #ifdef HAVE_KW_THREAD
-__thread RememberedSet *remembered_set MONO_TLS_FAST;
+static __thread RememberedSet *remembered_set MONO_TLS_FAST;
 #endif
 static MonoNativeTlsKey remembered_set_key;
-RememberedSet *global_remset;
-RememberedSet *freed_thread_remsets;
-GenericStoreRememberedSet *generic_store_remsets = NULL;
+static RememberedSet *global_remset;
+static RememberedSet *freed_thread_remsets;
+static GenericStoreRememberedSet *generic_store_remsets = NULL;
 
 #ifdef HEAVY_STATISTICS
 static int stat_wbarrier_generic_store_remset = 0;
@@ -69,6 +69,9 @@ static long long stat_global_remsets_discarded = 0;
 
 #endif
 
+static gboolean global_remset_location_was_not_added (gpointer ptr);
+
+
 static void
 clear_thread_store_remset_buffer (SgenThreadInfo *info)
 {
@@ -123,7 +126,7 @@ mono_sgen_alloc_remset (int size, gpointer id, gboolean global)
 
 
 
-void
+static void
 mono_sgen_ssb_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* value)
 {
        RememberedSet *rs;
@@ -148,7 +151,7 @@ mono_sgen_ssb_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObjec
        UNLOCK_GC;
 }
 
-void
+static void
 mono_sgen_ssb_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* value)
 {
        RememberedSet *rs;
@@ -173,7 +176,7 @@ mono_sgen_ssb_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObje
        UNLOCK_GC;
 }
 
-void
+static void
 mono_sgen_ssb_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
 {
        RememberedSet *rs;
@@ -201,7 +204,7 @@ mono_sgen_ssb_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int c
        UNLOCK_GC;
 }
 
-void
+static void
 mono_sgen_ssb_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass)
 {
        RememberedSet *rs;
@@ -236,7 +239,7 @@ mono_sgen_ssb_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoC
        UNLOCK_GC;
 }      
 
-void
+static void
 mono_sgen_ssb_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
 {
        int size;
@@ -269,7 +272,7 @@ mono_sgen_ssb_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
        UNLOCK_GC;
 }
 
-void
+static void
 mono_sgen_ssb_wbarrier_generic_nostore (gpointer ptr)
 {
        gpointer *buffer;
@@ -415,7 +418,7 @@ handle_remset (mword *p, void *start_nursery, void *end_nursery, gboolean global
                        major_collector.copy_object (ptr, queue);
                        DEBUG (9, fprintf (gc_debug_file, "Overwrote remset at %p with %p\n", ptr, *ptr));
                        if (old)
-                               binary_protocol_ptr_update (ptr, old, *ptr, (gpointer)LOAD_VTABLE (*ptr), safe_object_get_size (*ptr));
+                               binary_protocol_ptr_update (ptr, old, *ptr, (gpointer)LOAD_VTABLE (*ptr), mono_sgen_safe_object_get_size (*ptr));
                        if (!global && *ptr >= start_nursery && *ptr < end_nursery) {
                                /*
                                 * If the object is pinned, each reference to it from nonpinned objects
@@ -469,8 +472,8 @@ handle_remset (mword *p, void *start_nursery, void *end_nursery, gboolean global
        return NULL;
 }
 
-void
-mono_sgen_ssb_scan_from_global_remsets (void *start_nursery, void *end_nursery, SgenGrayQueue *queue)
+static void
+mono_sgen_ssb_begin_scan_remsets (void *start_nursery, void *end_nursery, SgenGrayQueue *queue)
 {
        RememberedSet *remset;
        mword *p, *next_p, *store_pos;
@@ -508,8 +511,8 @@ mono_sgen_ssb_scan_from_global_remsets (void *start_nursery, void *end_nursery,
        }
 }
 
-void
-mono_sgen_ssb_scan_from_remsets (void *start_nursery, void *end_nursery, SgenGrayQueue *queue)
+static void
+mono_sgen_ssb_finish_scan_remsets (void *start_nursery, void *end_nursery, SgenGrayQueue *queue)
 {
        int i;
        SgenThreadInfo *info;
@@ -574,7 +577,7 @@ mono_sgen_ssb_scan_from_remsets (void *start_nursery, void *end_nursery, SgenGra
 }
 
 
-void
+static void
 mono_sgen_ssb_cleanup_thread (SgenThreadInfo *p)
 {
        RememberedSet *rset;
@@ -606,7 +609,7 @@ mono_sgen_ssb_cleanup_thread (SgenThreadInfo *p)
        *p->store_remset_buffer_addr = NULL;
 }
 
-void
+static void
 mono_sgen_ssb_register_thread (SgenThreadInfo *info)
 {
 #ifndef HAVE_KW_THREAD
@@ -623,7 +626,16 @@ mono_sgen_ssb_register_thread (SgenThreadInfo *info)
        STORE_REMSET_BUFFER_INDEX = 0;
 }
 
-void
+#ifdef HAVE_KW_THREAD
+static void
+mono_sgen_ssb_fill_thread_info_for_suspend (SgenThreadInfo *info)
+{
+       /* update the remset info in the thread data structure */
+       info->remset = remembered_set;
+}
+#endif
+
+static void
 mono_sgen_ssb_prepare_for_minor_collection (void)
 {
        memset (global_remset_cache, 0, sizeof (global_remset_cache));
@@ -634,7 +646,7 @@ mono_sgen_ssb_prepare_for_minor_collection (void)
  * the per-thread ones are not needed and the global ones will be reconstructed
  * during the copy.
  */
-void
+static void
 mono_sgen_ssb_prepare_for_major_collection (void)
 {
        SgenThreadInfo *info;
@@ -692,7 +704,7 @@ mono_sgen_ssb_prepare_for_major_collection (void)
  *
  * Returns TRUE is the element was added..
  */
-gboolean
+static gboolean
 global_remset_location_was_not_added (gpointer ptr)
 {
 
@@ -718,7 +730,7 @@ global_remset_location_was_not_added (gpointer ptr)
        return TRUE;
 }
 
-void
+static void
 mono_sgen_ssb_record_pointer (gpointer ptr)
 {
        RememberedSet *rs;
@@ -768,8 +780,120 @@ mono_sgen_ssb_record_pointer (gpointer ptr)
                UNLOCK_GLOBAL_REMSET;
 }
 
+/*
+ * ######################################################################
+ * ########  Debug support
+ * ######################################################################
+ */
+
+static mword*
+find_in_remset_loc (mword *p, char *addr, gboolean *found)
+{
+       void **ptr;
+       mword count, desc;
+       size_t skip_size;
+
+       switch ((*p) & REMSET_TYPE_MASK) {
+       case REMSET_LOCATION:
+               if (*p == (mword)addr)
+                       *found = TRUE;
+               return p + 1;
+       case REMSET_RANGE:
+               ptr = (void**)(*p & ~REMSET_TYPE_MASK);
+               count = p [1];
+               if ((void**)addr >= ptr && (void**)addr < ptr + count)
+                       *found = TRUE;
+               return p + 2;
+       case REMSET_OBJECT:
+               ptr = (void**)(*p & ~REMSET_TYPE_MASK);
+               count = mono_sgen_safe_object_get_size ((MonoObject*)ptr); 
+               count = SGEN_ALIGN_UP (count);
+               count /= sizeof (mword);
+               if ((void**)addr >= ptr && (void**)addr < ptr + count)
+                       *found = TRUE;
+               return p + 1;
+       case REMSET_VTYPE:
+               ptr = (void**)(*p & ~REMSET_TYPE_MASK);
+               desc = p [1];
+               count = p [2];
+               skip_size = p [3];
+
+               /* The descriptor includes the size of MonoObject */
+               skip_size -= sizeof (MonoObject);
+               skip_size *= count;
+               if ((void**)addr >= ptr && (void**)addr < ptr + (skip_size / sizeof (gpointer)))
+                       *found = TRUE;
+
+               return p + 4;
+       default:
+               g_assert_not_reached ();
+       }
+       return NULL;
+}
+/*
+ * Return whenever ADDR occurs in the remembered sets
+ */
+static gboolean
+mono_sgen_ssb_find_address (char *addr)
+{
+       int i;
+       SgenThreadInfo *info;
+       RememberedSet *remset;
+       GenericStoreRememberedSet *store_remset;
+       mword *p;
+       gboolean found = FALSE;
+
+       /* the global one */
+       for (remset = global_remset; remset; remset = remset->next) {
+               DEBUG (4, fprintf (gc_debug_file, "Scanning global remset range: %p-%p, size: %td\n", remset->data, remset->store_next, remset->store_next - remset->data));
+               for (p = remset->data; p < remset->store_next;) {
+                       p = find_in_remset_loc (p, addr, &found);
+                       if (found)
+                               return TRUE;
+               }
+       }
+
+       /* the generic store ones */
+       for (store_remset = generic_store_remsets; store_remset; store_remset = store_remset->next) {
+               for (i = 0; i < STORE_REMSET_BUFFER_SIZE - 1; ++i) {
+                       if (store_remset->data [i] == addr)
+                               return TRUE;
+               }
+       }
+
+       /* the per-thread ones */
+       FOREACH_THREAD (info) {
+               int j;
+               for (remset = info->remset; remset; remset = remset->next) {
+                       DEBUG (4, fprintf (gc_debug_file, "Scanning remset for thread %p, range: %p-%p, size: %td\n", info, remset->data, remset->store_next, remset->store_next - remset->data));
+                       for (p = remset->data; p < remset->store_next;) {
+                               p = find_in_remset_loc (p, addr, &found);
+                               if (found)
+                                       return TRUE;
+                       }
+               }
+               for (j = 0; j < *info->store_remset_buffer_index_addr; ++j) {
+                       if ((*info->store_remset_buffer_addr) [j + 1] == addr)
+                               return TRUE;
+               }
+       } END_FOREACH_THREAD
+
+       /* the freed thread ones */
+       for (remset = freed_thread_remsets; remset; remset = remset->next) {
+               DEBUG (4, fprintf (gc_debug_file, "Scanning remset for freed thread, range: %p-%p, size: %td\n", remset->data, remset->store_next, remset->store_next - remset->data));
+               for (p = remset->data; p < remset->store_next;) {
+                       p = find_in_remset_loc (p, addr, &found);
+                       if (found)
+                               return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+
 void
-mono_sgen_ssb_init (void)
+mono_sgen_ssb_init (SgenRemeberedSet *remset)
 {
        LOCK_INIT (global_remset_mutex);
 
@@ -791,6 +915,27 @@ mono_sgen_ssb_init (void)
        mono_counters_register ("Global remsets processed", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_global_remsets_processed);
        mono_counters_register ("Global remsets discarded", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_global_remsets_discarded);
 #endif
-}
 
+       remset->wbarrier_set_field = mono_sgen_ssb_wbarrier_set_field;
+       remset->wbarrier_set_arrayref = mono_sgen_ssb_wbarrier_set_arrayref;
+       remset->wbarrier_arrayref_copy = mono_sgen_ssb_wbarrier_arrayref_copy;
+       remset->wbarrier_value_copy = mono_sgen_ssb_wbarrier_value_copy;
+       remset->wbarrier_object_copy = mono_sgen_ssb_wbarrier_object_copy;
+       remset->wbarrier_generic_nostore = mono_sgen_ssb_wbarrier_generic_nostore;
+       remset->record_pointer = mono_sgen_ssb_record_pointer;
+
+       remset->begin_scan_remsets = mono_sgen_ssb_begin_scan_remsets;
+       remset->finish_scan_remsets = mono_sgen_ssb_finish_scan_remsets;
+
+       remset->register_thread = mono_sgen_ssb_register_thread;
+       remset->cleanup_thread = mono_sgen_ssb_cleanup_thread;
+#ifdef HAVE_KW_THREAD
+       remset->fill_thread_info_for_suspend = mono_sgen_ssb_fill_thread_info_for_suspend;
+#endif
+
+       remset->prepare_for_minor_collection = mono_sgen_ssb_prepare_for_minor_collection;
+       remset->prepare_for_major_collection = mono_sgen_ssb_prepare_for_major_collection;
+
+       remset->find_address = mono_sgen_ssb_find_address;
+}
 #endif