-/*
- * sgen-marksweep-drain-gray-stack.h: The copy/mark and gray stack
- * draining functions of the M&S major collector.
+/**
+ * \file
+ * The copy/mark and gray stack draining functions of the M&S major collector.
*
* Copyright (C) 2014 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;
- *
- * 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.
- *
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
#ifdef HEAVY_STATISTICS
++stat_optimized_copy;
{
- char *forwarded;
+ GCObject *forwarded;
SgenDescriptor desc;
if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj)))
desc = sgen_obj_get_descriptor_safe (forwarded);
#endif
SGEN_ASSERT (9, obj, "null object from pointer %p", ptr);
-#ifndef COPY_OR_MARK_CONCURRENT
+#if !defined(COPY_OR_MARK_CONCURRENT) && !defined(COPY_OR_MARK_CONCURRENT_WITH_EVACUATION)
SGEN_ASSERT (9, current_collection_generation == GENERATION_OLD, "old gen parallel allocator called from a %d collection", current_collection_generation);
#endif
if (sgen_ptr_in_nursery (obj)) {
-#ifndef COPY_OR_MARK_CONCURRENT
+#if !defined(COPY_OR_MARK_CONCURRENT) && !defined(COPY_OR_MARK_CONCURRENT_WITH_EVACUATION)
int word, bit;
+ gboolean first = TRUE;
GCObject *forwarded, *old_obj;
mword vtable_word = *(mword*)obj;
HEAVY_STAT (++stat_optimized_copy_nursery_pinned);
return TRUE;
}
- if ((forwarded = SGEN_VTABLE_IS_FORWARDED (vtable_word))) {
+ if ((forwarded = (GCObject *)SGEN_VTABLE_IS_FORWARDED (vtable_word))) {
HEAVY_STAT (++stat_optimized_copy_nursery_forwarded);
SGEN_UPDATE_REFERENCE (ptr, forwarded);
return sgen_ptr_in_nursery (forwarded);
do_copy_object:
#endif
old_obj = obj;
+#ifdef COPY_OR_MARK_PARALLEL
+ obj = copy_object_no_checks_par (obj, queue);
+#else
obj = copy_object_no_checks (obj, queue);
+#endif
if (G_UNLIKELY (old_obj == obj)) {
/*
* If we fail to evacuate an object we just stop doing it for a
block = MS_BLOCK_FOR_OBJ (obj);
MS_CALC_MARK_BIT (word, bit, obj);
SGEN_ASSERT (9, !MS_MARK_BIT (block, word, bit), "object %p already marked", obj);
+#ifdef COPY_OR_MARK_PARALLEL
+ MS_SET_MARK_BIT_PAR (block, word, bit, first);
+#else
MS_SET_MARK_BIT (block, word, bit);
- binary_protocol_mark (obj, (gpointer)LOAD_VTABLE (obj), sgen_safe_object_get_size (obj));
+#endif
+ if (first)
+ binary_protocol_mark (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size (obj));
return FALSE;
#endif
#ifdef COPY_OR_MARK_WITH_EVACUATION
{
GCObject *forwarded;
- if ((forwarded = SGEN_VTABLE_IS_FORWARDED (vtable_word))) {
+ if ((forwarded = (GCObject *)SGEN_VTABLE_IS_FORWARDED (vtable_word))) {
HEAVY_STAT (++stat_optimized_copy_major_forwarded);
SGEN_UPDATE_REFERENCE (ptr, forwarded);
SGEN_ASSERT (9, !sgen_ptr_in_nursery (forwarded), "Cannot be forwarded to nursery.");
SGEN_ASSERT (9, !SGEN_VTABLE_IS_PINNED (vtable_word), "Pinned object in non-pinned block?");
- desc = sgen_vtable_get_descriptor ((GCVTable)vtable_word);
+ /* We untag the vtable for concurrent M&S, in case bridge is running and it tagged it */
+ desc = sgen_vtable_get_descriptor ((GCVTable)SGEN_POINTER_UNTAG_VTABLE (vtable_word));
type = desc & DESC_TYPE_MASK;
if (sgen_safe_object_is_small (obj, type)) {
block = MS_BLOCK_FOR_OBJ (obj);
-#ifdef COPY_OR_MARK_CONCURRENT
+#ifdef COPY_OR_MARK_CONCURRENT_WITH_EVACUATION
if (G_UNLIKELY (major_block_is_evacuating (block))) {
/*
* We don't copy within the concurrent phase. These objects will
}
#endif
+#ifdef COPY_OR_MARK_PARALLEL
+ MS_MARK_OBJECT_AND_ENQUEUE_PAR (obj, desc, block, queue);
+#else
MS_MARK_OBJECT_AND_ENQUEUE (obj, desc, block, queue);
+#endif
} else {
+ gboolean first = TRUE;
HEAVY_STAT (++stat_optimized_copy_major_large);
-
+#ifdef COPY_OR_MARK_PARALLEL
+ first = sgen_los_pin_object_par (obj);
+#else
if (sgen_los_object_is_pinned (obj))
- return FALSE;
- binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size (obj));
+ first = FALSE;
+ else
+ sgen_los_pin_object (obj);
+#endif
- sgen_los_pin_object (obj);
- if (SGEN_OBJECT_HAS_REFERENCES (obj))
- GRAY_OBJECT_ENQUEUE (queue, obj, sgen_obj_get_descriptor (obj));
+ if (first) {
+ binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size (obj));
+ if (SGEN_OBJECT_HAS_REFERENCES (obj))
+#ifdef COPY_OR_MARK_PARALLEL
+ GRAY_OBJECT_ENQUEUE_PARALLEL (queue, obj, desc);
+#else
+ GRAY_OBJECT_ENQUEUE_SERIAL (queue, obj, desc);
+#endif
+ }
}
return FALSE;
}
/* Now scan the object. */
#undef HANDLE_PTR
-#ifdef COPY_OR_MARK_CONCURRENT
+#if defined(COPY_OR_MARK_CONCURRENT_WITH_EVACUATION)
#define HANDLE_PTR(ptr,obj) do { \
GCObject *__old = *(ptr); \
binary_protocol_scan_process_reference ((full_object), (ptr), __old); \
if (__old && !sgen_ptr_in_nursery (__old)) { \
- MSBlockInfo *block = MS_BLOCK_FOR_OBJ (__old); \
- if (G_UNLIKELY (!sgen_ptr_in_nursery (ptr) && \
+ if (G_UNLIKELY (full_object && !sgen_ptr_in_nursery (ptr) && \
sgen_safe_object_is_small (__old, sgen_obj_get_descriptor (__old) & DESC_TYPE_MASK) && \
- major_block_is_evacuating (block))) { \
+ major_block_is_evacuating (MS_BLOCK_FOR_OBJ (__old)))) { \
mark_mod_union_card ((full_object), (void**)(ptr), __old); \
} else { \
PREFETCH_READ (__old); \
COPY_OR_MARK_FUNCTION_NAME ((ptr), __old, queue); \
} \
} else { \
- if (G_UNLIKELY (sgen_ptr_in_nursery (__old) && !sgen_ptr_in_nursery ((ptr)))) \
+ if (G_UNLIKELY (full_object && sgen_ptr_in_nursery (__old) && !sgen_ptr_in_nursery ((ptr)) && !sgen_cement_is_forced (__old))) \
+ mark_mod_union_card ((full_object), (void**)(ptr), __old); \
+ } \
+ } while (0)
+#elif defined(COPY_OR_MARK_CONCURRENT)
+#define HANDLE_PTR(ptr,obj) do { \
+ GCObject *__old = *(ptr); \
+ binary_protocol_scan_process_reference ((full_object), (ptr), __old); \
+ if (__old && !sgen_ptr_in_nursery (__old)) { \
+ PREFETCH_READ (__old); \
+ COPY_OR_MARK_FUNCTION_NAME ((ptr), __old, queue); \
+ } else { \
+ if (G_UNLIKELY (full_object && sgen_ptr_in_nursery (__old) && !sgen_ptr_in_nursery ((ptr)) && !sgen_cement_is_forced (__old))) \
mark_mod_union_card ((full_object), (void**)(ptr), __old); \
} \
} while (0)
#else
#define HANDLE_PTR(ptr,obj) do { \
- void *__old = *(ptr); \
+ GCObject *__old = *(ptr); \
binary_protocol_scan_process_reference ((full_object), (ptr), __old); \
if (__old) { \
gboolean __still_in_nursery = COPY_OR_MARK_FUNCTION_NAME ((ptr), __old, queue); \
if (G_UNLIKELY (__still_in_nursery && !sgen_ptr_in_nursery ((ptr)) && !SGEN_OBJECT_IS_CEMENTED (*(ptr)))) { \
- void *__copy = *(ptr); \
+ GCObject *__copy = *(ptr); \
sgen_add_to_global_remset ((ptr), __copy); \
} \
} \
#include "sgen-scan-object.h"
}
+#ifdef SCAN_VTYPE_FUNCTION_NAME
+static void
+SCAN_VTYPE_FUNCTION_NAME (GCObject *full_object, char *start, SgenDescriptor desc, SgenGrayQueue *queue BINARY_PROTOCOL_ARG (size_t size))
+{
+ SGEN_OBJECT_LAYOUT_STATISTICS_DECLARE_BITMAP;
+
+#ifdef HEAVY_STATISTICS
+ /* FIXME: We're half scanning this object. How do we account for that? */
+ //add_scanned_object (start);
+#endif
+
+ /* The descriptors include info about the object header as well */
+ start -= SGEN_CLIENT_OBJECT_HEADER_SIZE;
+
+ /* We use the same HANDLE_PTR from the obj scan function */
+#define SCAN_OBJECT_NOVTABLE
+#define SCAN_OBJECT_PROTOCOL
+#include "sgen-scan-object.h"
+
+ SGEN_OBJECT_LAYOUT_STATISTICS_COMMIT_BITMAP;
+}
+#endif
+
+#ifdef SCAN_PTR_FIELD_FUNCTION_NAME
+static void
+SCAN_PTR_FIELD_FUNCTION_NAME (GCObject *full_object, GCObject **ptr, SgenGrayQueue *queue)
+{
+ /*
+ * full_object is NULL if we scan unmanaged memory. This means we can't mark
+ * mod unions for it, so these types of roots currently don't have support
+ * for the concurrent collector (aka they need to be scanned as normal roots
+ * both in the start and finishing pause)
+ */
+ HANDLE_PTR (ptr, NULL);
+}
+#endif
+
static gboolean
DRAIN_GRAY_STACK_FUNCTION_NAME (SgenGrayQueue *queue)
{
-#ifdef COPY_OR_MARK_CONCURRENT
+#if defined(COPY_OR_MARK_CONCURRENT) || defined(COPY_OR_MARK_CONCURRENT_WITH_EVACUATION) || defined(COPY_OR_MARK_PARALLEL)
int i;
for (i = 0; i < 32; i++) {
#else
HEAVY_STAT (++stat_drain_loops);
- GRAY_OBJECT_DEQUEUE (queue, &obj, &desc);
+#if defined(COPY_OR_MARK_PARALLEL)
+ GRAY_OBJECT_DEQUEUE_PARALLEL (queue, &obj, &desc);
+#else
+ GRAY_OBJECT_DEQUEUE_SERIAL (queue, &obj, &desc);
+#endif
if (!obj)
return TRUE;
return FALSE;
}
+#undef COPY_OR_MARK_PARALLEL
#undef COPY_OR_MARK_FUNCTION_NAME
#undef COPY_OR_MARK_WITH_EVACUATION
+#undef COPY_OR_MARK_CONCURRENT
+#undef COPY_OR_MARK_CONCURRENT_WITH_EVACUATION
#undef SCAN_OBJECT_FUNCTION_NAME
+#undef SCAN_VTYPE_FUNCTION_NAME
+#undef SCAN_PTR_FIELD_FUNCTION_NAME
#undef DRAIN_GRAY_STACK_FUNCTION_NAME