Merge remote-tracking branch 'joncham/sgen-msvc2'
[mono.git] / mono / metadata / sgen-gc.c
index e6a0bec947927159f12f0ddcb07e9750a6299b2a..3431875933b56b7d6cdfccc95ded9beb1c5262c4 100644 (file)
 #include "metadata/sgen-archdep.h"
 #include "metadata/sgen-bridge.h"
 #include "metadata/sgen-memory-governor.h"
+#include "metadata/sgen-hash-table.h"
 #include "metadata/mono-gc.h"
 #include "metadata/method-builder.h"
 #include "metadata/profiler-private.h"
 #include "utils/mono-proclib.h"
 #include "utils/mono-memory-model.h"
 #include "utils/mono-logger-internal.h"
+#include "utils/dtrace.h"
 
 #include <mono/utils/mono-logger-internal.h>
 #include <mono/utils/memcheck.h>
@@ -1244,6 +1246,11 @@ pin_objects_from_addresses (GCMemSection *section, void **start, void **end, voi
                                        if (addr >= search_start && (char*)addr < (char*)last_obj + last_obj_size) {
                                                DEBUG (4, fprintf (gc_debug_file, "Pinned object %p, vtable %p (%s), count %d\n", search_start, *(void**)search_start, safe_name (search_start), count));
                                                binary_protocol_pin (search_start, (gpointer)LOAD_VTABLE (search_start), safe_object_get_size (search_start));
+                                               if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
+                                                       int gen = sgen_ptr_in_nursery (search_start) ? GENERATION_NURSERY : GENERATION_OLD;
+                                                       MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (search_start);
+                                                       MONO_GC_OBJ_PINNED ((mword)search_start, sgen_safe_object_get_size (search_start), vt->klass->name_space, vt->klass->name, gen);
+                                               }
                                                pin_object (search_start);
                                                GRAY_OBJECT_ENQUEUE (queue, search_start);
                                                if (G_UNLIKELY (do_pin_stats))
@@ -1309,6 +1316,11 @@ sgen_pin_object (void *object, GrayQueue *queue)
        }
        GRAY_OBJECT_ENQUEUE (queue, object);
        binary_protocol_pin (object, (gpointer)LOAD_VTABLE (object), safe_object_get_size (object));
+       if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
+               int gen = sgen_ptr_in_nursery (object) ? GENERATION_NURSERY : GENERATION_OLD;
+               MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (object);
+               MONO_GC_OBJ_PINNED ((mword)object, sgen_safe_object_get_size (object), vt->klass->name_space, vt->klass->name, gen);
+       }
 }
 
 void
@@ -1637,7 +1649,7 @@ alloc_nursery (void)
        section->size = alloc_size;
        section->end_data = data + sgen_nursery_size;
        scan_starts = (alloc_size + SCAN_START_SIZE - 1) / SCAN_START_SIZE;
-       section->scan_starts = sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS);
+       section->scan_starts = sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS, TRUE);
        section->num_scan_start = scan_starts;
        section->block.role = MEMORY_ROLE_GEN0;
        section->block.next = NULL;
@@ -1812,9 +1824,9 @@ stw_bridge_process (void)
 }
 
 static void
-bridge_process (void)
+bridge_process (int generation)
 {
-       sgen_bridge_processing_finish ();
+       sgen_bridge_processing_finish (generation);
 }
 
 SgenObjectOperations *
@@ -2351,6 +2363,8 @@ collect_nursery (void)
        if (disable_minor_collections)
                return TRUE;
 
+       MONO_GC_BEGIN (GENERATION_NURSERY);
+
        verify_nursery ();
 
        mono_perfcounters->gc_collections0++;
@@ -2400,7 +2414,7 @@ collect_nursery (void)
        sgen_workers_init_distribute_gray_queue ();
 
        stat_minor_gcs++;
-       mono_stats.minor_gc_count ++;
+       gc_stats.minor_gc_count ++;
 
        if (remset.prepare_for_minor_collection)
                remset.prepare_for_minor_collection ();
@@ -2542,7 +2556,7 @@ collect_nursery (void)
        major_collector.finish_nursery_collection ();
 
        TV_GETTIME (all_btv);
-       mono_stats.minor_gc_time_usecs += TV_ELAPSED (all_atv, all_btv);
+       gc_stats.minor_gc_time_usecs += TV_ELAPSED (all_atv, all_btv);
 
        if (heap_dump_file)
                dump_heap ("minor", stat_minor_gcs - 1, NULL);
@@ -2571,6 +2585,8 @@ collect_nursery (void)
        current_collection_generation = -1;
        objects_pinned = 0;
 
+       MONO_GC_END (GENERATION_NURSERY);
+
        return needs_major;
 }
 
@@ -2592,6 +2608,8 @@ major_do_collection (const char *reason)
        ScanThreadDataJobData stdjd;
        ScanFinalizerEntriesJobData sfejd_fin_ready, sfejd_critical_fin;
 
+       MONO_GC_BEGIN (GENERATION_OLD);
+
        current_collection_generation = GENERATION_OLD;
        mono_perfcounters->gc_collections1++;
 
@@ -2614,7 +2632,7 @@ major_do_collection (const char *reason)
        degraded_mode = 0;
        DEBUG (1, fprintf (gc_debug_file, "Start major collection %d\n", stat_major_gcs));
        stat_major_gcs++;
-       mono_stats.major_gc_count ++;
+       gc_stats.major_gc_count ++;
 
        /* world must be stopped already */
        TV_GETTIME (all_atv);
@@ -2682,6 +2700,10 @@ major_do_collection (const char *reason)
                report.count = 0;
                if (sgen_find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + bigobj->size, &dummy)) {
                        binary_protocol_pin (bigobj->data, (gpointer)LOAD_VTABLE (bigobj->data), safe_object_get_size (bigobj->data));
+                       if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
+                               MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (bigobj->data);
+                               MONO_GC_OBJ_PINNED ((mword)bigobj->data, sgen_safe_object_get_size ((MonoObject*)bigobj->data), vt->klass->name_space, vt->klass->name, GENERATION_OLD);
+                       }
                        pin_object (bigobj->data);
                        /* FIXME: only enqueue if object has references */
                        GRAY_OBJECT_ENQUEUE (WORKERS_DISTRIBUTE_GRAY_QUEUE, bigobj->data);
@@ -2851,7 +2873,7 @@ major_do_collection (const char *reason)
        time_major_fragment_creation += TV_ELAPSED (btv, atv);
 
        TV_GETTIME (all_btv);
-       mono_stats.major_gc_time_usecs += TV_ELAPSED (all_atv, all_btv);
+       gc_stats.major_gc_time_usecs += TV_ELAPSED (all_atv, all_btv);
 
        if (heap_dump_file)
                dump_heap ("major", stat_major_gcs - 1, reason);
@@ -2878,6 +2900,8 @@ major_do_collection (const char *reason)
 
        //consistency_check ();
 
+       MONO_GC_END (GENERATION_OLD);
+
        return bytes_pinned_from_failed_allocation > 0;
 }
 
@@ -3419,12 +3443,14 @@ update_current_thread_stack (void *start)
 #ifdef USE_MONO_CTX
        MONO_CONTEXT_GET_CURRENT (cur_thread_ctx);
        info->monoctx = &cur_thread_ctx;
+       if (gc_callbacks.thread_suspend_func)
+               gc_callbacks.thread_suspend_func (info->runtime_data, NULL, info->monoctx);
 #else
        ARCH_STORE_REGS (reg_ptr);
        info->stopped_regs = reg_ptr;
-#endif
        if (gc_callbacks.thread_suspend_func)
-               gc_callbacks.thread_suspend_func (info->runtime_data, NULL);
+               gc_callbacks.thread_suspend_func (info->runtime_data, NULL, NULL);
+#endif
 }
 
 void
@@ -3598,7 +3624,7 @@ restart_world (int generation, GGTimingInfo *timing)
        DEBUG (2, fprintf (gc_debug_file, "restarted %d thread(s) (pause time: %d usec, max: %d)\n", count, (int)usec, (int)max_pause_usec));
        mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD, generation);
 
-       bridge_process ();
+       bridge_process (generation);
 
        TV_GETTIME (end_bridge);
        bridge_usec = TV_ELAPSED (end_sw, end_bridge);
@@ -3877,6 +3903,7 @@ sgen_thread_unregister (SgenThreadInfo *p)
                if (!sgen_park_current_thread_if_doing_handshake (p))
                        g_usleep (50);
        }
+       MONO_GC_LOCKED ();
 #endif
 
        binary_protocol_thread_unregister ((gpointer)mono_thread_info_get_tid (p));
@@ -4388,9 +4415,27 @@ mono_gc_weak_link_remove (void **link_addr)
 MonoObject*
 mono_gc_weak_link_get (void **link_addr)
 {
-       if (!*link_addr)
+       /*
+        * We must only load *link_addr once because it might change
+        * under our feet, and REVEAL_POINTER (NULL) results in an
+        * invalid reference.
+        */
+       void *ptr = *link_addr;
+       if (!ptr)
                return NULL;
-       return (MonoObject*) REVEAL_POINTER (*link_addr);
+
+       /*
+        * During the second bridge processing step the world is
+        * running again.  That step processes all weak links once
+        * more to null those that refer to dead objects.  Before that
+        * is completed, those links must not be followed, so we
+        * conservatively wait for bridge processing when any weak
+        * link is dereferenced.
+        */
+       if (G_UNLIKELY (bridge_processing_in_progress))
+               mono_gc_wait_for_bridge_processing ();
+
+       return (MonoObject*) REVEAL_POINTER (ptr);
 }
 
 gboolean
@@ -4599,6 +4644,9 @@ mono_gc_base_init (void)
                                                        fprintf (stderr, "The major collector does not support the cardtable write barrier.\n");
                                                exit (1);
                                        }
+                               } else {
+                                       fprintf (stderr, "wbarrier must either be `remset' or `cardtable'.");
+                                       exit (1);
                                }
                                continue;
                        }
@@ -4899,6 +4947,12 @@ mono_gc_is_critical_method (MonoMethod *method)
        return (method == write_barrier_method || sgen_is_managed_allocator (method));
 }
 
+static gboolean
+sgen_has_critical_method (void)
+{
+       return write_barrier_method || sgen_has_managed_allocator ();
+}
+
 static gboolean
 is_ip_in_managed_allocator (MonoDomain *domain, gpointer ip)
 {
@@ -4910,6 +4964,8 @@ is_ip_in_managed_allocator (MonoDomain *domain, gpointer ip)
 
        if (!ip || !domain)
                return FALSE;
+       if (!sgen_has_critical_method ())
+               return FALSE;
        ji = mono_jit_info_table_find (domain, ip);
        if (!ji)
                return FALSE;