Introduce a callback API to have notifications when runtime resources exceed preset...
[mono.git] / mono / metadata / sgen-major-copy-object.h
index a5061e66cf40833e42afdbab0aba2e67d4bd385e..7ed69b5ba48f48245aeb84f17f0cd75ee84aece6 100644 (file)
@@ -1,3 +1,26 @@
+/*
+ * Copyright 2001-2003 Ximian, Inc
+ * Copyright 2003-2010 Novell, Inc.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
 extern long long stat_copy_object_called_nursery;
 extern long long stat_objects_copied_nursery;
 
@@ -18,7 +41,6 @@ par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword o
        DEBUG (9, fprintf (gc_debug_file, " (to %p, %s size: %lu)\n", destination, ((MonoObject*)obj)->vtable->klass->name, (unsigned long)objsize));
        binary_protocol_copy (obj, destination, vt, objsize);
 
-       *(MonoVTable**)destination = vt;
        if (objsize <= sizeof (gpointer) * 8) {
                mword *dest = (mword*)destination;
                goto *copy_labels [objsize / sizeof (gpointer)];
@@ -41,7 +63,8 @@ par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword o
        LAB_0:
                ;
        } else {
-               memcpy (destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword));
+               /*can't trust memcpy doing word copies */
+               mono_gc_memmove (destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword));
        }
        /* adjust array->bounds */
        DEBUG (9, g_assert (vt->gc_descr));
@@ -54,7 +77,7 @@ par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword o
                mono_sgen_register_moved_object (obj, destination);
        obj = destination;
        if (queue) {
-               DEBUG (9, fprintf (gc_debug_file, "Enqueuing gray object %p (%s)\n", obj, safe_name (obj)));
+               DEBUG (9, fprintf (gc_debug_file, "Enqueuing gray object %p (%s)\n", obj, mono_sgen_safe_name (obj)));
                GRAY_OBJECT_ENQUEUE (queue, obj);
        }
 }
@@ -67,6 +90,18 @@ copy_object_no_checks (void *obj, SgenGrayQueue *queue)
        mword objsize = SGEN_ALIGN_UP (mono_sgen_par_object_get_size (vt, (MonoObject*)obj));
        char *destination = major_alloc_object (objsize, has_references);
 
+       if (G_UNLIKELY (!destination)) {
+               if (ptr_in_nursery (obj)) {
+                       mono_sgen_pin_object (obj, queue);
+               } else {
+                       g_assert (objsize <= SGEN_MAX_SMALL_OBJ_SIZE);
+                       pin_major_object (obj, queue);
+               }
+               mono_sgen_set_pinned_from_failed_allocation (objsize);
+               return obj;
+       }
+
+       *(MonoVTable**)destination = vt;
        par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL);
 
        /* set the forwarding pointer */
@@ -96,7 +131,7 @@ copy_object_no_checks (void *obj, SgenGrayQueue *queue)
  */
 
 static void
-copy_object (void **obj_slot, SgenGrayQueue *queue)
+nopar_copy_object (void **obj_slot, SgenGrayQueue *queue)
 {
        char *forwarded;
        char *obj = *obj_slot;
@@ -119,14 +154,14 @@ copy_object (void **obj_slot, SgenGrayQueue *queue)
         */
 
        if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) {
-               DEBUG (9, g_assert (((MonoVTable*)LOAD_VTABLE(obj))->gc_descr));
+               DEBUG (9, g_assert (((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr));
                DEBUG (9, fprintf (gc_debug_file, " (already forwarded to %p)\n", forwarded));
                HEAVY_STAT (++stat_nursery_copy_object_failed_forwarded);
                *obj_slot = forwarded;
                return;
        }
        if (SGEN_OBJECT_IS_PINNED (obj)) {
-               DEBUG (9, g_assert (((MonoVTable*)LOAD_VTABLE(obj))->gc_descr));
+               DEBUG (9, g_assert (((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr));
                DEBUG (9, fprintf (gc_debug_file, " (pinned, no change)\n"));
                HEAVY_STAT (++stat_nursery_copy_object_failed_pinned);
                return;
@@ -137,6 +172,87 @@ copy_object (void **obj_slot, SgenGrayQueue *queue)
        *obj_slot = copy_object_no_checks (obj, queue);
 }
 
+#ifdef SGEN_PARALLEL_MARK
+static void
+copy_object (void **obj_slot, SgenGrayQueue *queue)
+{
+       char *obj = *obj_slot;
+       mword vtable_word, objsize;
+       MonoVTable *vt;
+       void *destination;
+       gboolean has_references;
+
+       DEBUG (9, g_assert (current_collection_generation == GENERATION_NURSERY));
+
+       HEAVY_STAT (++stat_copy_object_called_nursery);
+
+       if (!ptr_in_nursery (obj)) {
+               HEAVY_STAT (++stat_nursery_copy_object_failed_from_space);
+               return;
+       }
+
+       vtable_word = *(mword*)obj;
+       vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
+
+       /*
+        * Before we can copy the object we must make sure that we are
+        * allowed to, i.e. that the object not pinned or not already
+        * forwarded.
+        */
+
+       if (vtable_word & SGEN_FORWARDED_BIT) {
+               HEAVY_STAT (++stat_nursery_copy_object_failed_forwarded);
+               *obj_slot = vt;
+               return;
+       }
+       if (vtable_word & SGEN_PINNED_BIT) {
+               HEAVY_STAT (++stat_nursery_copy_object_failed_pinned);
+               return;
+       }
+
+       HEAVY_STAT (++stat_objects_copied_nursery);
+
+       objsize = SGEN_ALIGN_UP (mono_sgen_par_object_get_size (vt, (MonoObject*)obj));
+       has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
+
+       destination = alloc_obj_par (objsize, FALSE, has_references);
+
+       if (G_UNLIKELY (!destination)) {
+               pin_or_update_par (obj_slot, obj, vt, queue);
+               return;
+       }
+
+       *(MonoVTable**)destination = vt;
+
+       if (SGEN_CAS_PTR ((void*)obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) {
+               par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL);
+               obj = destination;
+               *obj_slot = obj;
+       } else {
+               /* FIXME: unify with code in major_copy_or_mark_object() */
+
+               /* FIXME: Give destination back to the allocator. */
+               *(void**)destination = NULL;
+
+               vtable_word = *(mword*)obj;
+               g_assert (vtable_word & SGEN_FORWARDED_BIT);
+
+               obj = (void*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
+
+               *obj_slot = obj;
+
+               ++stat_slots_allocated_in_vain;
+       }
+}
+#else
+static void
+copy_object (void **obj_slot, SgenGrayQueue *queue)
+{
+       nopar_copy_object (obj_slot, queue);
+}
+#endif
+
 #define FILL_COLLECTOR_COPY_OBJECT(collector)  do {                    \
                (collector)->copy_object = copy_object;                 \
+               (collector)->nopar_copy_object = nopar_copy_object;     \
        } while (0)