Merge pull request #2961 from schani/fix-sgen-refactoring
[mono.git] / mono / metadata / sgen-mono.c
index 339a4de7e4057eff833cd9db1a9de4b605a9ba35..33e01a8fb28717c98abc9e1f0a1978f156a81676 100644 (file)
@@ -140,7 +140,8 @@ mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
 
        HEAVY_STAT (++stat_wbarrier_object_copy);
 
-       if (sgen_ptr_in_nursery (obj) || ptr_on_stack (obj) || !SGEN_OBJECT_HAS_REFERENCES (src)) {
+       SGEN_ASSERT (6, !ptr_on_stack (obj), "Why is this called for a non-reference type?");
+       if (sgen_ptr_in_nursery (obj) || !SGEN_OBJECT_HAS_REFERENCES (src)) {
                size = mono_object_class (obj)->instance_size;
                mono_gc_memmove_aligned ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject),
                                size - sizeof (MonoObject));
@@ -525,17 +526,19 @@ object_in_domain_predicate (MonoObject *obj, void *user_data)
  * @out_array: output array
  * @out_size: size of output array
  *
- * Store inside @out_array up to @out_size objects that belong to the unloading
- * appdomain @domain. Returns the number of stored items. Can be called repeteadly
- * until it returns 0.
- * The items are removed from the finalizer data structure, so the caller is supposed
- * to finalize them.
- * @out_array should be on the stack to allow the GC to know the objects are still alive.
+ * Enqueue for finalization all objects that belong to the unloading appdomain @domain
+ * @suspend is used for early termination of the enqueuing process.
  */
-int
-mono_gc_finalizers_for_domain (MonoDomain *domain, MonoObject **out_array, int out_size)
+void
+mono_gc_finalize_domain (MonoDomain *domain)
+{
+       sgen_finalize_if (object_in_domain_predicate, domain);
+}
+
+void
+mono_gc_suspend_finalizers (void)
 {
-       return sgen_gather_finalizers_if (object_in_domain_predicate, domain, out_array, out_size);
+       sgen_set_suspend_finalizers ();
 }
 
 /*
@@ -841,7 +844,7 @@ mono_gc_clear_domain (MonoDomain * domain)
        sgen_stop_world (0);
 
        if (sgen_concurrent_collection_in_progress ())
-               sgen_perform_collection (0, GENERATION_OLD, "clear domain", TRUE);
+               sgen_perform_collection (0, GENERATION_OLD, "clear domain", TRUE, FALSE);
        SGEN_ASSERT (0, !sgen_concurrent_collection_in_progress (), "We just ordered a synchronous collection.  Why are we collecting concurrently?");
 
        major_collector.finish_sweeping ();
@@ -1145,14 +1148,6 @@ create_allocator (int atype, ManagedAllocatorVariant variant)
 
        EMIT_TLS_ACCESS_VAR (mb, thread_var);
 
-#ifdef MANAGED_ALLOCATOR_CAN_USE_CRITICAL_REGION
-       EMIT_TLS_ACCESS_IN_CRITICAL_REGION_ADDR (mb, thread_var);
-       mono_mb_emit_byte (mb, CEE_LDC_I4_1);
-       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-       mono_mb_emit_byte (mb, CEE_MONO_ATOMIC_STORE_I4);
-       mono_mb_emit_i4 (mb, MONO_MEMORY_BARRIER_NONE);
-#endif
-
        size_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
        if (atype == ATYPE_SMALL) {
                /* size_var = size_arg */
@@ -1279,6 +1274,14 @@ create_allocator (int atype, ManagedAllocatorVariant variant)
                g_assert_not_reached ();
        }
 
+#ifdef MANAGED_ALLOCATOR_CAN_USE_CRITICAL_REGION
+       EMIT_TLS_ACCESS_IN_CRITICAL_REGION_ADDR (mb, thread_var);
+       mono_mb_emit_byte (mb, CEE_LDC_I4_1);
+       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+       mono_mb_emit_byte (mb, CEE_MONO_ATOMIC_STORE_I4);
+       mono_mb_emit_i4 (mb, MONO_MEMORY_BARRIER_NONE);
+#endif
+
        /* size += ALLOC_ALIGN - 1; */
        mono_mb_emit_ldloc (mb, size_var);
        mono_mb_emit_icon (mb, SGEN_ALLOC_ALIGN - 1);
@@ -1330,6 +1333,18 @@ create_allocator (int atype, ManagedAllocatorVariant variant)
 
        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
        mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
+       /*
+        * We are no longer in a critical section. We need to do this before calling
+        * to unmanaged land in order to avoid stw deadlocks since unmanaged code
+        * might take locks.
+        */
+#ifdef MANAGED_ALLOCATOR_CAN_USE_CRITICAL_REGION
+       EMIT_TLS_ACCESS_IN_CRITICAL_REGION_ADDR (mb, thread_var);
+       mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+       mono_mb_emit_byte (mb, CEE_MONO_ATOMIC_STORE_I4);
+       mono_mb_emit_i4 (mb, MONO_MEMORY_BARRIER_NONE);
+#endif
 
        /* FIXME: mono_gc_alloc_obj takes a 'size_t' as an argument, not an int32 */
        mono_mb_emit_ldarg (mb, 0);
@@ -1357,11 +1372,6 @@ create_allocator (int atype, ManagedAllocatorVariant variant)
        mono_mb_emit_ldloc (mb, new_next_var);
        mono_mb_emit_byte (mb, CEE_STIND_I);
 
-       /*The tlab store must be visible before the the vtable store. This could be replaced with a DDS but doing it with IL would be tricky. */
-       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-       mono_mb_emit_byte (mb, CEE_MONO_MEMORY_BARRIER);
-       mono_mb_emit_i4 (mb, MONO_MEMORY_BARRIER_REL);
-
        /* *p = vtable; */
        mono_mb_emit_ldloc (mb, p_var);
        mono_mb_emit_ldarg (mb, 0);
@@ -2243,6 +2253,8 @@ sgen_client_thread_register (SgenThreadInfo* info, void *stack_bottom_fallback)
        binary_protocol_thread_register ((gpointer)mono_thread_info_get_tid (info));
 
        SGEN_LOG (3, "registered thread %p (%p) stack end %p", info, (gpointer)mono_thread_info_get_tid (info), info->client_info.stack_end);
+
+       info->client_info.info.handle_stack = mono_handle_stack_alloc ();
 }
 
 void
@@ -2268,6 +2280,10 @@ sgen_client_thread_unregister (SgenThreadInfo *p)
 
        binary_protocol_thread_unregister ((gpointer)tid);
        SGEN_LOG (3, "unregister thread %p (%p)", p, (gpointer)tid);
+
+       HandleStack *handles = (HandleStack*) p->client_info.info.handle_stack;
+       p->client_info.info.handle_stack = NULL;
+       mono_handle_stack_free (handles);
 }
 
 void
@@ -2295,8 +2311,6 @@ thread_in_critical_region (SgenThreadInfo *info)
 static void
 sgen_thread_attach (SgenThreadInfo *info)
 {
-       mono_handle_arena_init ((MonoHandleArena**) &info->client_info.info.handle_arena);
-
        if (mono_gc_get_gc_callbacks ()->thread_attach_func && !info->client_info.runtime_data)
                info->client_info.runtime_data = mono_gc_get_gc_callbacks ()->thread_attach_func ();
 }
@@ -2312,8 +2326,6 @@ sgen_thread_detach (SgenThreadInfo *p)
         */
        if (mono_domain_get ())
                mono_thread_detach_internal (mono_thread_internal_current ());
-
-       mono_handle_arena_cleanup ((MonoHandleArena**) &p->client_info.info.handle_arena);
 }
 
 gboolean
@@ -2402,6 +2414,7 @@ sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean p
                                fprintf (stderr, "Precise stack mark not supported - disabling.\n");
                                conservative_stack_mark = TRUE;
                        }
+                       //FIXME we should eventually use the new stack_mark from coop
                        sgen_conservatively_pin_objects_from ((void **)aligned_stack_start, (void **)info->client_info.stack_end, start_nursery, end_nursery, PIN_TYPE_STACK);
                }
 
@@ -2412,6 +2425,7 @@ sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean p
                        {
                                // This is used on Coop GC for platforms where we cannot get the data for individual registers.
                                // We force a spill of all registers into the stack and pass a chunk of data into sgen.
+                               //FIXME under coop, for now, what we need to ensure is that we scan any extra memory from info->client_info.stack_end to stack_mark
                                MonoThreadUnwindState *state = &info->client_info.info.thread_saved_state [SELF_SUSPEND_STATE_INDEX];
                                if (state && state->gc_stackdata) {
                                        sgen_conservatively_pin_objects_from ((void **)state->gc_stackdata, (void**)((char*)state->gc_stackdata + state->gc_stackdata_size),
@@ -2419,6 +2433,9 @@ sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean p
                                }
                        }
                }
+               if (precise && info->client_info.info.handle_stack) {
+                       mono_handle_stack_scan ((HandleStack*)info->client_info.info.handle_stack, (GcScanFunc)ctx.ops->copy_or_mark_object, ctx.queue);
+               }
        } FOREACH_THREAD_END
 }
 
@@ -2520,7 +2537,11 @@ mono_gc_get_gc_name (void)
 char*
 mono_gc_get_description (void)
 {
+#ifdef HAVE_CONC_GC_AS_DEFAULT
+       return g_strdup ("sgen (concurrent by default)");
+#else
        return g_strdup ("sgen");
+#endif
 }
 
 void