-#define GRAY_QUEUE_SECTION_SIZE (128 - 3)
-#define GRAY_QUEUE_LENGTH_LIMIT 64
-
/*
- * This is a stack now instead of a queue, so the most recently added items are removed
- * first, improving cache locality, and keeping the stack size manageable.
+ * 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.
*/
-typedef struct _GrayQueueSection GrayQueueSection;
-struct _GrayQueueSection {
- int end;
- GrayQueueSection *next, *prev;
- char *objects [GRAY_QUEUE_SECTION_SIZE];
-};
-
-static GrayQueueSection *gray_queue_start = NULL;
-static GrayQueueSection *gray_queue_end = NULL;
+#define GRAY_QUEUE_LENGTH_LIMIT 64
-static int gray_queue_balance = 0;
-static int num_gray_queue_sections = 0;
+static GrayQueue gray_queue;
static void
-gray_object_alloc_queue_section (void)
+gray_object_alloc_queue_section (GrayQueue *queue)
{
GrayQueueSection *section;
- /* Use the previously allocated queue sections if possible */
- if (!gray_queue_end && gray_queue_start) {
- gray_queue_end = gray_queue_start;
- gray_queue_end->end = 0;
- return;
- }
- if (gray_queue_end && gray_queue_end->next) {
- gray_queue_end = gray_queue_end->next;
- gray_queue_end->end = 0;
- return;
- }
+ if (queue->alloc_prepare_func)
+ queue->alloc_prepare_func (queue);
- /* Allocate a new section */
- section = get_internal_mem (sizeof (GrayQueueSection), INTERNAL_MEM_GRAY_QUEUE);
- ++num_gray_queue_sections;
+ if (queue->free_list) {
+ /* Use the previously allocated queue sections if possible */
+ section = queue->free_list;
+ queue->free_list = section->next;
+ } else {
+ /* Allocate a new section */
+ section = mono_sgen_alloc_internal_fixed (queue->allocator, INTERNAL_MEM_GRAY_QUEUE);
+ }
section->end = 0;
- section->next = NULL;
- section->prev = NULL;
/* Link it with the others */
- if (gray_queue_end) {
- gray_queue_end->next = section;
- section->prev = gray_queue_end;
- } else {
- g_assert (!gray_queue_start);
- gray_queue_start = section;
- }
- gray_queue_end = section;
+ section->next = queue->first;
+ queue->first = section;
}
static void
-gray_object_free_queue_section (GrayQueueSection *section)
+gray_object_free_queue_section (GrayQueueSection *section, SgenInternalAllocator *thread_allocator)
{
- free_internal_mem (section, INTERNAL_MEM_GRAY_QUEUE);
- --num_gray_queue_sections;
+ mono_sgen_free_internal_delayed (section, INTERNAL_MEM_GRAY_QUEUE, thread_allocator);
}
-/*
- * The following three functions are called in the inner loops of the collector, so they
- * need to be as fast as possible.
- */
-
-static inline void
-gray_object_enqueue (char *obj)
+static inline gboolean
+gray_object_queue_is_empty (GrayQueue *queue)
{
- g_assert (obj);
- if (G_UNLIKELY (!gray_queue_end || gray_queue_end->end == GRAY_QUEUE_SECTION_SIZE))
- gray_object_alloc_queue_section ();
- g_assert (gray_queue_end && gray_queue_end->end < GRAY_QUEUE_SECTION_SIZE);
- gray_queue_end->objects [gray_queue_end->end++] = obj;
-
- ++gray_queue_balance;
+ return queue->first == NULL;
}
-static inline gboolean
-gray_object_queue_is_empty (void)
+/*
+ * The following two functions are called in the inner loops of the
+ * collector, so they need to be as fast as possible. We have macros
+ * for them in sgen-gc.h.
+ */
+
+void
+mono_sgen_gray_object_enqueue (GrayQueue *queue, char *obj)
{
- return gray_queue_end == NULL;
+ DEBUG (9, g_assert (obj));
+ if (G_UNLIKELY (!queue->first || queue->first->end == SGEN_GRAY_QUEUE_SECTION_SIZE))
+ gray_object_alloc_queue_section (queue);
+ DEBUG (9, g_assert (queue->first && queue->first->end < SGEN_GRAY_QUEUE_SECTION_SIZE));
+ queue->first->objects [queue->first->end++] = obj;
+
+ DEBUG (9, ++queue->balance);
}
-static inline char*
-gray_object_dequeue (void)
+char*
+mono_sgen_gray_object_dequeue (GrayQueue *queue)
{
char *obj;
- if (gray_object_queue_is_empty ())
+ if (gray_object_queue_is_empty (queue))
return NULL;
- g_assert (gray_queue_end->end);
+ DEBUG (9, g_assert (queue->first->end));
- obj = gray_queue_end->objects [--gray_queue_end->end];
+ obj = queue->first->objects [--queue->first->end];
- if (G_UNLIKELY (gray_queue_end->end == 0))
- gray_queue_end = gray_queue_end->prev;
+ if (G_UNLIKELY (queue->first->end == 0)) {
+ GrayQueueSection *section = queue->first;
+ queue->first = section->next;
+ section->next = queue->free_list;
+ queue->free_list = section;
+ }
- --gray_queue_balance;
+ DEBUG (9, --queue->balance);
return obj;
}
+static GrayQueueSection*
+gray_object_dequeue_section (GrayQueue *queue)
+{
+ GrayQueueSection *section;
+
+ if (!queue->first)
+ return NULL;
+
+ section = queue->first;
+ queue->first = section->next;
+
+ section->next = NULL;
+
+ return section;
+}
+
static void
-gray_object_queue_init (void)
+gray_object_enqueue_section (GrayQueue *queue, GrayQueueSection *section)
+{
+ section->next = queue->first;
+ queue->first = section;
+}
+
+static void
+gray_object_queue_init (GrayQueue *queue, SgenInternalAllocator *allocator)
{
GrayQueueSection *section, *next;
int i;
- g_assert (gray_object_queue_is_empty ());
- g_assert (sizeof (GrayQueueSection) < MAX_FREELIST_SIZE);
- g_assert (gray_queue_balance == 0);
+ g_assert (gray_object_queue_is_empty (queue));
+ DEBUG (9, g_assert (queue->balance == 0));
+
+ queue->allocator = allocator;
/* Free the extra sections allocated during the last collection */
i = 0;
- for (section = gray_queue_start; section && i < GRAY_QUEUE_LENGTH_LIMIT; section = section->next)
+ for (section = queue->free_list; section && i < GRAY_QUEUE_LENGTH_LIMIT - 1; section = section->next)
i ++;
- if (section) {
- if (section->prev)
- section->prev->next = NULL;
- for (; section; section = next) {
- next = section->next;
- gray_object_free_queue_section (section);
- }
+ if (!section)
+ return;
+ while (section->next) {
+ next = section->next;
+ section->next = next->next;
+ gray_object_free_queue_section (next, allocator);
}
}
+
+static void
+gray_object_queue_init_with_alloc_prepare (GrayQueue *queue, SgenInternalAllocator *allocator, GrayQueueAllocPrepareFunc func, void *data)
+{
+ gray_object_queue_init (queue, allocator);
+ queue->alloc_prepare_func = func;
+ queue->alloc_prepare_data = data;
+}