2 * sgen-marksweep-drain-gray-stack.h: The copy/mark and gray stack
3 * draining functions of the M&S major collector.
5 * Copyright (C) 2014 Xamarin Inc
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License 2.0 as published by the Free Software Foundation;
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License 2.0 along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * COPY_OR_MARK_FUNCTION_NAME must be defined to be the function name of the copy/mark
25 * SCAN_OBJECT_FUNCTION_NAME must be defined to be the function name of the object scanning
28 * DRAIN_GRAY_STACK_FUNCTION_NAME must be defined to be the function name of the gray stack
31 * Define COPY_OR_MARK_WITH_EVACUATION to support evacuation.
34 /* Returns whether the object is still in the nursery. */
35 static inline MONO_ALWAYS_INLINE gboolean
36 COPY_OR_MARK_FUNCTION_NAME (void **ptr, void *obj, SgenGrayQueue *queue)
40 #ifdef HEAVY_STATISTICS
41 ++stat_optimized_copy;
45 if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj)))
46 desc = sgen_obj_get_descriptor_safe (forwarded);
48 desc = sgen_obj_get_descriptor_safe (obj);
50 sgen_descriptor_count_copied_object (desc);
54 SGEN_ASSERT (9, obj, "null object from pointer %p", ptr);
55 SGEN_ASSERT (9, current_collection_generation == GENERATION_OLD, "old gen parallel allocator called from a %d collection", current_collection_generation);
57 if (sgen_ptr_in_nursery (obj)) {
59 char *forwarded, *old_obj;
60 mword vtable_word = *(mword*)obj;
62 HEAVY_STAT (++stat_optimized_copy_nursery);
64 #if SGEN_MAX_DEBUG_LEVEL >= 9
65 if (sgen_nursery_is_to_space (obj))
66 SGEN_ASSERT (9, !SGEN_VTABLE_IS_PINNED (vtable_word) && !SGEN_VTABLE_IS_FORWARDED (vtable_word), "To-space object can't be pinned or forwarded.");
69 if (SGEN_VTABLE_IS_PINNED (vtable_word)) {
70 SGEN_ASSERT (9, !SGEN_VTABLE_IS_FORWARDED (vtable_word), "Cannot be both pinned and forwarded.");
71 HEAVY_STAT (++stat_optimized_copy_nursery_pinned);
74 if ((forwarded = SGEN_VTABLE_IS_FORWARDED (vtable_word))) {
75 HEAVY_STAT (++stat_optimized_copy_nursery_forwarded);
76 SGEN_UPDATE_REFERENCE (ptr, forwarded);
77 return sgen_ptr_in_nursery (forwarded);
80 /* An object in the nursery To Space has already been copied and grayed. Nothing to do. */
81 if (sgen_nursery_is_to_space (obj))
84 #ifdef COPY_OR_MARK_WITH_EVACUATION
88 obj = copy_object_no_checks (obj, queue);
89 if (G_UNLIKELY (old_obj == obj)) {
91 * If we fail to evacuate an object we just stop doing it for a
92 * given block size as all other will surely fail too.
94 /* FIXME: test this case somehow. */
95 if (!sgen_ptr_in_nursery (obj)) {
97 block = MS_BLOCK_FOR_OBJ (obj);
98 size_index = block->obj_size_index;
99 evacuate_block_obj_sizes [size_index] = FALSE;
100 MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue);
105 HEAVY_STAT (++stat_objects_copied_major);
106 SGEN_UPDATE_REFERENCE (ptr, obj);
108 if (sgen_ptr_in_nursery (obj))
112 * FIXME: See comment for copy_object_no_checks(). If
113 * we have that, we can let the allocation function
114 * give us the block info, too, and we won't have to
117 * FIXME (2): We should rework this to avoid all those nursery checks.
120 * For the split nursery allocator the object might
121 * still be in the nursery despite having being
122 * promoted, in which case we can't mark it.
124 block = MS_BLOCK_FOR_OBJ (obj);
125 MS_CALC_MARK_BIT (word, bit, obj);
126 SGEN_ASSERT (9, !MS_MARK_BIT (block, word, bit), "object %p already marked", obj);
127 MS_SET_MARK_BIT (block, word, bit);
128 binary_protocol_mark (obj, (gpointer)LOAD_VTABLE (obj), sgen_safe_object_get_size ((GCObject*)obj));
132 mword vtable_word = *(mword*)obj;
136 HEAVY_STAT (++stat_optimized_copy_major);
138 #ifdef COPY_OR_MARK_WITH_EVACUATION
141 if ((forwarded = SGEN_VTABLE_IS_FORWARDED (vtable_word))) {
142 HEAVY_STAT (++stat_optimized_copy_major_forwarded);
143 SGEN_UPDATE_REFERENCE (ptr, forwarded);
144 SGEN_ASSERT (9, !sgen_ptr_in_nursery (forwarded), "Cannot be forwarded to nursery.");
150 SGEN_ASSERT (9, !SGEN_VTABLE_IS_PINNED (vtable_word), "Pinned object in non-pinned block?");
152 desc = sgen_vtable_get_descriptor ((GCVTable*)vtable_word);
153 type = desc & DESC_TYPE_MASK;
155 if (sgen_safe_object_is_small ((GCObject*)obj, type)) {
156 #ifdef HEAVY_STATISTICS
157 if (type <= DESC_TYPE_MAX_SMALL_OBJ)
158 ++stat_optimized_copy_major_small_fast;
160 ++stat_optimized_copy_major_small_slow;
163 block = MS_BLOCK_FOR_OBJ (obj);
165 #ifdef COPY_OR_MARK_WITH_EVACUATION
167 int size_index = block->obj_size_index;
169 if (evacuate_block_obj_sizes [size_index] && !block->has_pinned) {
170 HEAVY_STAT (++stat_optimized_copy_major_small_evacuate);
171 if (block->is_to_space)
178 MS_MARK_OBJECT_AND_ENQUEUE (obj, desc, block, queue);
180 HEAVY_STAT (++stat_optimized_copy_major_large);
182 if (sgen_los_object_is_pinned (obj))
184 binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size ((GCObject*)obj));
186 sgen_los_pin_object (obj);
187 if (SGEN_OBJECT_HAS_REFERENCES (obj))
188 GRAY_OBJECT_ENQUEUE (queue, obj, sgen_obj_get_descriptor (obj));
192 SGEN_ASSERT (0, FALSE, "How is this happening?");
197 SCAN_OBJECT_FUNCTION_NAME (char *obj, mword desc, SgenGrayQueue *queue)
201 #ifdef HEAVY_STATISTICS
202 ++stat_optimized_major_scan;
203 if (!sgen_gc_descr_has_references (desc))
204 ++stat_optimized_major_scan_no_refs;
205 sgen_descriptor_count_scanned_object (desc);
207 #ifdef SGEN_HEAVY_BINARY_PROTOCOL
208 add_scanned_object (start);
211 /* Now scan the object. */
214 #define HANDLE_PTR(ptr,obj) do { \
215 void *__old = *(ptr); \
216 binary_protocol_scan_process_reference ((obj), (ptr), __old); \
218 gboolean __still_in_nursery = COPY_OR_MARK_FUNCTION_NAME ((ptr), __old, queue); \
219 if (G_UNLIKELY (__still_in_nursery && !sgen_ptr_in_nursery ((ptr)) && !SGEN_OBJECT_IS_CEMENTED (*(ptr)))) { \
220 void *__copy = *(ptr); \
221 sgen_add_to_global_remset ((ptr), __copy); \
226 #define SCAN_OBJECT_PROTOCOL
227 #include "sgen-scan-object.h"
231 DRAIN_GRAY_STACK_FUNCTION_NAME (ScanCopyContext ctx)
233 SgenGrayQueue *queue = ctx.queue;
235 SGEN_ASSERT (0, ctx.ops->scan_object == major_scan_object_with_evacuation, "Wrong scan function");
241 HEAVY_STAT (++stat_drain_loops);
243 GRAY_OBJECT_DEQUEUE (queue, &obj, &desc);
247 SCAN_OBJECT_FUNCTION_NAME (obj, desc, ctx.queue);
251 #undef COPY_OR_MARK_FUNCTION_NAME
252 #undef COPY_OR_MARK_WITH_EVACUATION
253 #undef SCAN_OBJECT_FUNCTION_NAME
254 #undef DRAIN_GRAY_STACK_FUNCTION_NAME