2 * sgen-gray.c: Gray queue management.
4 * Copyright 2001-2003 Ximian, Inc
5 * Copyright 2003-2010 Novell, Inc.
6 * Copyright (C) 2012 Xamarin Inc
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License 2.0 as published by the Free Software Foundation;
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License 2.0 along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "metadata/sgen-gc.h"
25 #include "utils/mono-counters.h"
26 #include "sgen-protocol.h"
28 #define GRAY_QUEUE_LENGTH_LIMIT 64
30 #ifdef SGEN_CHECK_GRAY_OBJECT_SECTIONS
31 #define STATE_TRANSITION(s,o,n) do { \
33 if (InterlockedCompareExchange ((volatile int*)&(s)->state, (n), __old) != __old) \
34 g_assert_not_reached (); \
36 #define STATE_SET(s,v) (s)->state = (v)
37 #define STATE_ASSERT(s,v) g_assert ((s)->state == (v))
39 #define STATE_TRANSITION(s,o,n)
40 #define STATE_SET(s,v)
41 #define STATE_ASSERT(s,v)
45 sgen_gray_object_alloc_queue_section (SgenGrayQueue *queue)
47 GrayQueueSection *section;
49 HEAVY_STAT (gc_stats.gray_queue_section_alloc ++);
51 if (queue->alloc_prepare_func)
52 queue->alloc_prepare_func (queue);
54 if (queue->free_list) {
55 /* Use the previously allocated queue sections if possible */
56 section = queue->free_list;
57 queue->free_list = section->next;
58 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FREE_LIST, GRAY_QUEUE_SECTION_STATE_FLOATING);
60 /* Allocate a new section */
61 section = sgen_alloc_internal (INTERNAL_MEM_GRAY_QUEUE);
62 STATE_SET (section, GRAY_QUEUE_SECTION_STATE_FLOATING);
65 section->size = SGEN_GRAY_QUEUE_SECTION_SIZE;
67 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
69 /* Link it with the others */
70 section->next = queue->first;
71 queue->first = section;
72 queue->cursor = (char**)section->objects - 1;
76 sgen_gray_object_free_queue_section (GrayQueueSection *section)
78 HEAVY_STAT (gc_stats.gray_queue_section_free ++);
80 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_FREED);
81 sgen_free_internal (section, INTERNAL_MEM_GRAY_QUEUE);
85 * The following two functions are called in the inner loops of the
86 * collector, so they need to be as fast as possible. We have macros
87 * for them in sgen-gc.h.
91 sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj)
93 HEAVY_STAT (gc_stats.gray_queue_enqueue_slow_path ++);
95 SGEN_ASSERT (9, obj, "enqueueing a null object");
96 //sgen_check_objref (obj);
98 #ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
99 if (queue->enqueue_check_func)
100 queue->enqueue_check_func (obj);
103 if (G_UNLIKELY (!queue->first || queue->cursor == GRAY_LAST_CURSOR_POSITION (queue->first))) {
105 /* Set the current section size back to default, might have been changed by sgen_gray_object_dequeue_section */
106 queue->first->size = SGEN_GRAY_QUEUE_SECTION_SIZE;
109 sgen_gray_object_alloc_queue_section (queue);
111 STATE_ASSERT (queue->first, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
112 SGEN_ASSERT (9, queue->cursor <= GRAY_LAST_CURSOR_POSITION (queue->first), "gray queue %p overflow, first %p, cursor %p", queue, queue->first, queue->cursor);
113 *++queue->cursor = obj;
115 #ifdef SGEN_HEAVY_BINARY_PROTOCOL
116 binary_protocol_gray_enqueue (queue, queue->cursor, obj);
121 sgen_gray_object_dequeue (SgenGrayQueue *queue)
125 HEAVY_STAT (gc_stats.gray_queue_dequeue_slow_path ++);
127 if (sgen_gray_object_queue_is_empty (queue))
130 STATE_ASSERT (queue->first, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
131 SGEN_ASSERT (9, queue->cursor >= (char**)queue->first->objects, "gray queue %p underflow, first %p, cursor %d", queue, queue->first, queue->cursor);
133 obj = *queue->cursor--;
135 #ifdef SGEN_HEAVY_BINARY_PROTOCOL
136 binary_protocol_gray_dequeue (queue, queue->cursor + 1, obj);
139 if (G_UNLIKELY (queue->cursor == (char**)queue->first->objects - 1)) {
140 GrayQueueSection *section = queue->first;
141 queue->first = section->next;
142 section->next = queue->free_list;
144 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_ENQUEUED, GRAY_QUEUE_SECTION_STATE_FREE_LIST);
146 queue->free_list = section;
147 queue->cursor = queue->first ? (char**)queue->first->objects + queue->first->size - 1 : NULL;
154 sgen_gray_object_dequeue_section (SgenGrayQueue *queue)
156 GrayQueueSection *section;
161 section = queue->first;
162 queue->first = section->next;
164 section->next = NULL;
165 section->size = queue->cursor - (char**)section->objects + 1;
167 queue->cursor = queue->first ? (char**)queue->first->objects + queue->first->size - 1 : NULL;
169 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_ENQUEUED, GRAY_QUEUE_SECTION_STATE_FLOATING);
175 sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *section)
177 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
180 queue->first->size = queue->cursor - (char**)queue->first->objects + 1;
182 section->next = queue->first;
183 queue->first = section;
184 queue->cursor = (char**)queue->first->objects + queue->first->size - 1;
185 #ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
186 if (queue->enqueue_check_func) {
188 for (i = 0; i < section->size; ++i)
189 queue->enqueue_check_func (section->objects [i]);
195 sgen_gray_object_queue_init (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func)
197 GrayQueueSection *section, *next;
200 g_assert (sgen_gray_object_queue_is_empty (queue));
202 queue->alloc_prepare_func = NULL;
203 queue->alloc_prepare_data = NULL;
204 #ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
205 queue->enqueue_check_func = enqueue_check_func;
208 /* Free the extra sections allocated during the last collection */
210 for (section = queue->free_list; section && i < GRAY_QUEUE_LENGTH_LIMIT - 1; section = section->next) {
211 STATE_ASSERT (section, GRAY_QUEUE_SECTION_STATE_FREE_LIST);
216 while (section->next) {
217 next = section->next;
218 section->next = next->next;
219 STATE_TRANSITION (next, GRAY_QUEUE_SECTION_STATE_FREE_LIST, GRAY_QUEUE_SECTION_STATE_FLOATING);
220 sgen_gray_object_free_queue_section (next);
225 invalid_prepare_func (SgenGrayQueue *queue)
227 g_assert_not_reached ();
231 sgen_gray_object_queue_init_invalid (SgenGrayQueue *queue)
233 sgen_gray_object_queue_init (queue, FALSE);
234 queue->alloc_prepare_func = invalid_prepare_func;
235 queue->alloc_prepare_data = NULL;
239 sgen_gray_object_queue_init_with_alloc_prepare (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func,
240 GrayQueueAllocPrepareFunc alloc_prepare_func, void *data)
242 sgen_gray_object_queue_init (queue, enqueue_check_func);
243 queue->alloc_prepare_func = alloc_prepare_func;
244 queue->alloc_prepare_data = data;
248 sgen_gray_object_queue_deinit (SgenGrayQueue *queue)
250 g_assert (!queue->first);
251 while (queue->free_list) {
252 GrayQueueSection *next = queue->free_list->next;
253 STATE_TRANSITION (queue->free_list, GRAY_QUEUE_SECTION_STATE_FREE_LIST, GRAY_QUEUE_SECTION_STATE_FLOATING);
254 sgen_gray_object_free_queue_section (queue->free_list);
255 queue->free_list = next;
260 sgen_gray_object_queue_disable_alloc_prepare (SgenGrayQueue *queue)
262 queue->alloc_prepare_func = NULL;
263 queue->alloc_prepare_data = NULL;
267 lock_section_queue (SgenSectionGrayQueue *queue)
272 mono_mutex_lock (&queue->lock);
276 unlock_section_queue (SgenSectionGrayQueue *queue)
281 mono_mutex_unlock (&queue->lock);
285 sgen_section_gray_queue_init (SgenSectionGrayQueue *queue, gboolean locked, GrayQueueEnqueueCheckFunc enqueue_check_func)
287 g_assert (sgen_section_gray_queue_is_empty (queue));
289 queue->locked = locked;
291 mono_mutex_init_recursive (&queue->lock);
294 #ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
295 queue->enqueue_check_func = enqueue_check_func;
300 sgen_section_gray_queue_is_empty (SgenSectionGrayQueue *queue)
302 return !queue->first;
306 sgen_section_gray_queue_dequeue (SgenSectionGrayQueue *queue)
308 GrayQueueSection *section;
310 lock_section_queue (queue);
313 section = queue->first;
314 queue->first = section->next;
316 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_ENQUEUED, GRAY_QUEUE_SECTION_STATE_FLOATING);
318 section->next = NULL;
323 unlock_section_queue (queue);
329 sgen_section_gray_queue_enqueue (SgenSectionGrayQueue *queue, GrayQueueSection *section)
331 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
333 lock_section_queue (queue);
335 section->next = queue->first;
336 queue->first = section;
337 #ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
338 if (queue->enqueue_check_func) {
340 for (i = 0; i < section->size; ++i)
341 queue->enqueue_check_func (section->objects [i]);
345 unlock_section_queue (queue);