Merge pull request #498 from Unroll-Me/master
[mono.git] / mono / metadata / sgen-gray.c
1 /*
2  * sgen-gray.c: Gray queue management.
3  *
4  * Copyright 2001-2003 Ximian, Inc
5  * Copyright 2003-2010 Novell, Inc.
6  * Copyright (C) 2012 Xamarin Inc
7  *
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;
11  *
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.
16  *
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.
20  */
21 #include "config.h"
22 #ifdef HAVE_SGEN_GC
23
24 #include "metadata/sgen-gc.h"
25 #include "utils/mono-counters.h"
26
27 #define GRAY_QUEUE_LENGTH_LIMIT 64
28
29 void
30 sgen_gray_object_alloc_queue_section (SgenGrayQueue *queue)
31 {
32         GrayQueueSection *section;
33
34         if (queue->alloc_prepare_func)
35                 queue->alloc_prepare_func (queue);
36
37         if (queue->free_list) {
38                 /* Use the previously allocated queue sections if possible */
39                 section = queue->free_list;
40                 queue->free_list = section->next;
41         } else {
42                 /* Allocate a new section */
43                 section = sgen_alloc_internal (INTERNAL_MEM_GRAY_QUEUE);
44         }
45
46         section->end = 0;
47
48         /* Link it with the others */
49         section->next = queue->first;
50         queue->first = section;
51 }
52
53 void
54 sgen_gray_object_free_queue_section (GrayQueueSection *section)
55 {
56         sgen_free_internal (section, INTERNAL_MEM_GRAY_QUEUE);
57 }
58
59 /*
60  * The following two functions are called in the inner loops of the
61  * collector, so they need to be as fast as possible.  We have macros
62  * for them in sgen-gc.h.
63  */
64
65 void
66 sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj)
67 {
68         SGEN_ASSERT (9, obj, "enqueueing a null object");
69         //sgen_check_objref (obj);
70         if (G_UNLIKELY (!queue->first || queue->first->end == SGEN_GRAY_QUEUE_SECTION_SIZE))
71                 sgen_gray_object_alloc_queue_section (queue);
72         SGEN_ASSERT (9, queue->first->end < SGEN_GRAY_QUEUE_SECTION_SIZE, "gray queue %p overflow, first %p, end %d", queue, queue->first, queue->first->end);
73         queue->first->objects [queue->first->end++] = obj;
74
75         SGEN_LOG_DO (9, ++queue->balance);
76 }
77
78 char*
79 sgen_gray_object_dequeue (SgenGrayQueue *queue)
80 {
81         char *obj;
82
83         if (sgen_gray_object_queue_is_empty (queue))
84                 return NULL;
85
86         SGEN_ASSERT (9, queue->first->end, "gray queue %p underflow, first %p, end %d", queue, queue->first, queue->first->end);
87
88         obj = queue->first->objects [--queue->first->end];
89
90         if (G_UNLIKELY (queue->first->end == 0)) {
91                 GrayQueueSection *section = queue->first;
92                 queue->first = section->next;
93                 section->next = queue->free_list;
94                 queue->free_list = section;
95         }
96
97         SGEN_LOG_DO (9, --queue->balance);
98
99         return obj;
100 }
101
102 GrayQueueSection*
103 sgen_gray_object_dequeue_section (SgenGrayQueue *queue)
104 {
105         GrayQueueSection *section;
106
107         if (!queue->first)
108                 return NULL;
109
110         section = queue->first;
111         queue->first = section->next;
112
113         section->next = NULL;
114
115         return section;
116 }
117
118 void
119 sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *section)
120 {
121         section->next = queue->first;
122         queue->first = section;
123 }
124
125 void
126 sgen_gray_object_queue_init (SgenGrayQueue *queue)
127 {
128         GrayQueueSection *section, *next;
129         int i;
130
131         g_assert (sgen_gray_object_queue_is_empty (queue));
132         SGEN_ASSERT (9, queue->balance == 0, "unbalanced queue on init %d", queue->balance);
133
134         /* Free the extra sections allocated during the last collection */
135         i = 0;
136         for (section = queue->free_list; section && i < GRAY_QUEUE_LENGTH_LIMIT - 1; section = section->next)
137                 i ++;
138         if (!section)
139                 return;
140         while (section->next) {
141                 next = section->next;
142                 section->next = next->next;
143                 sgen_gray_object_free_queue_section (next);
144         }
145 }
146
147 void
148 sgen_gray_object_queue_init_with_alloc_prepare (SgenGrayQueue *queue, GrayQueueAllocPrepareFunc func, void *data)
149 {
150         sgen_gray_object_queue_init (queue);
151         queue->alloc_prepare_func = func;
152         queue->alloc_prepare_data = data;
153 }
154
155 #endif