Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / sgen / sgen-copy-object.h
index 2b7bc60670a3751b20566b5c35f100d1b0d8ecf8..bb97e4a681689a2000318aeed0de938f8d8bfff6 100644 (file)
@@ -1,22 +1,33 @@
-/*
- * sgen-copy-object.h: This is where objects are copied.
+/**
+ * \file
+ * This is where objects are copied.
  *
  * Copyright 2001-2003 Ximian, Inc
  * Copyright 2003-2010 Novell, Inc.
  * Copyright (C) 2012 Xamarin Inc
  *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+/*
+ * Defines
+ *
+ *     GCObject* copy_object_no_checks (GCObject *obj, SgenGrayQueue *queue)
+ *
+ * which allocates new space for `obj`, copies it there, forwards `obj` to its new location,
+ * and enqueues the copy into `queue`.
+ *
+ * To be defined by the includer:
+ *
+ *     COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION(vt, obj, objsize, has_refs)
  *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
+ * Allocates space for promoting object `obj`, with size `objsize`, and initizializes the
+ * vtable with `vt`.  `has_refs` indicates whether the object contains references.
  *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *     collector_pin_object(obj, queue)
+ *
+ * Called when no space for `obj` could be allocated.  It must pin `obj` and enqueue it into
+ * `queue` for scanning.
  */
 
 extern guint64 stat_copy_object_called_nursery;
@@ -29,13 +40,11 @@ extern guint64 stat_nursery_copy_object_failed_pinned;
 extern guint64 stat_slots_allocated_in_vain;
 
 /*
- * Copies an object and enqueues it if a queue is given.
- *
  * This function can be used even if the vtable of obj is not valid
  * anymore, which is the case in the parallel collector.
  */
 static MONO_ALWAYS_INLINE void
-par_copy_object_no_checks (char *destination, GCVTable vt, void *obj, mword objsize, SgenGrayQueue *queue)
+par_copy_object_no_checks (char *destination, GCVTable vt, void *obj, mword objsize)
 {
        sgen_client_pre_copy_checks (destination, vt, obj, objsize);
        binary_protocol_copy (obj, destination, vt, objsize);
@@ -47,14 +56,10 @@ par_copy_object_no_checks (char *destination, GCVTable vt, void *obj, mword objs
        SGEN_ASSERT (9, sgen_vtable_get_descriptor (vt), "vtable %p has no gc descriptor", vt);
 
        sgen_client_update_copied_object (destination, vt, obj, objsize);
-       obj = destination;
-       if (queue) {
-               SGEN_LOG (9, "Enqueuing gray object %p (%s)", obj, sgen_client_vtable_get_name (vt));
-               GRAY_OBJECT_ENQUEUE (queue, (GCObject *)obj, sgen_vtable_get_descriptor (vt));
-       }
 }
 
 /*
+ * Copies an object and enqueues it if a queue is given.
  * This can return OBJ itself on OOM.
  */
 static MONO_NEVER_INLINE GCObject *
@@ -63,7 +68,6 @@ copy_object_no_checks (GCObject *obj, SgenGrayQueue *queue)
        GCVTable vt = SGEN_LOAD_VTABLE_UNCHECKED (obj);
        gboolean has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
        mword objsize = SGEN_ALIGN_UP (sgen_client_par_object_get_size (vt, obj));
-       /* FIXME: Does this not mark the newly allocated object? */
        void *destination = COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION (vt, obj, objsize, has_references);
 
        if (G_UNLIKELY (!destination)) {
@@ -73,14 +77,68 @@ copy_object_no_checks (GCObject *obj, SgenGrayQueue *queue)
                return obj;
        }
 
-       if (!has_references)
-               queue = NULL;
-
-       par_copy_object_no_checks ((char *)destination, vt, obj, objsize, queue);
-       /* FIXME: mark mod union cards if necessary */
+       par_copy_object_no_checks ((char *)destination, vt, obj, objsize);
 
        /* set the forwarding pointer */
        SGEN_FORWARD_OBJECT (obj, destination);
 
+       if (has_references) {
+               SGEN_LOG (9, "Enqueuing gray object %p (%s)", destination, sgen_client_vtable_get_name (vt));
+               GRAY_OBJECT_ENQUEUE_SERIAL (queue, (GCObject *)destination, sgen_vtable_get_descriptor (vt));
+       }
+
        return (GCObject *)destination;
 }
+
+#if defined(COPY_OR_MARK_PARALLEL)
+static MONO_NEVER_INLINE GCObject *
+copy_object_no_checks_par (GCObject *obj, SgenGrayQueue *queue)
+{
+       mword vtable_word = *(mword*)obj;
+       GCObject *destination;
+
+       destination = (GCObject*) SGEN_VTABLE_IS_FORWARDED (vtable_word);
+
+       if (!destination) {
+               GCVTable vt = (GCVTable) vtable_word;
+               GCObject *final_destination;
+               /*
+                * At this point we know vt is not tagged and we shouldn't access the vtable through obj
+                * since it could get copied at any time by another thread.
+                */
+               gboolean has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
+               mword objsize = SGEN_ALIGN_UP (sgen_client_par_object_get_size (vt, obj));
+               destination = COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION (vt, obj, objsize, has_references);
+
+               par_copy_object_no_checks ((char*)destination, vt, obj, objsize);
+
+               /* FIXME we might need a membar here so other threads see the vtable before we forward */
+
+               /* set the forwarding pointer */
+               SGEN_FORWARD_OBJECT_PAR (obj, destination, final_destination);
+
+               if (destination == final_destination) {
+                       /* In a racing case, only the worker that allocated the object enqueues it */
+                       if (has_references) {
+                               SGEN_LOG (9, "Enqueuing gray object %p (%s)", destination, sgen_client_vtable_get_name (vt));
+                               GRAY_OBJECT_ENQUEUE_PARALLEL (queue, (GCObject *)destination, sgen_vtable_get_descriptor (vt));
+                       }
+               } else {
+                       /*
+                        * Unlikely case. Clear the allocated object so it doesn't confuse nursery
+                        * card table scanning, since it can contain old invalid refs.
+                        * FIXME make sure it is not a problem if another threads scans it while we clear
+                        */
+                       mono_gc_bzero_aligned (destination, objsize);
+                       destination = final_destination;
+               }
+       }
+
+       return destination;
+}
+#endif
+
+#undef COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION
+#undef COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION
+#undef collector_pin_object
+#undef COPY_OR_MARK_PARALLEL