Merge pull request #241 from viniciusjarina/fix2843
[mono.git] / mono / metadata / sgen-gray.c
index 035f77a7b360315debe21471104f770cb7fd7ccd..04f81019254a650b2c96702c93184710b095c22b 100644 (file)
  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
-#define GRAY_QUEUE_SECTION_SIZE        (128 - 3)
-#define GRAY_QUEUE_LENGTH_LIMIT        64
+#include "config.h"
+#ifdef HAVE_SGEN_GC
 
-/*
- * 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.
- */
-typedef struct _GrayQueueSection GrayQueueSection;
-struct _GrayQueueSection {
-       int end;
-       GrayQueueSection *next, *prev;
-       char *objects [GRAY_QUEUE_SECTION_SIZE];
-};
+#include "metadata/sgen-gc.h"
+#include "utils/mono-counters.h"
 
-static GrayQueueSection *gray_queue_start = NULL;
-static GrayQueueSection *gray_queue_end = NULL;
-
-static int gray_queue_balance = 0;
-static int num_gray_queue_sections = 0;
+#define GRAY_QUEUE_LENGTH_LIMIT        64
 
-static void
-gray_object_alloc_queue_section (void)
+void
+mono_sgen_gray_object_alloc_queue_section (SgenGrayQueue *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 (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)
+void
+mono_sgen_gray_object_free_queue_section (GrayQueueSection *section)
 {
-       free_internal_mem (section, INTERNAL_MEM_GRAY_QUEUE);
-       --num_gray_queue_sections;
-}
-
-static inline gboolean
-gray_object_queue_is_empty (void)
-{
-       return gray_queue_end == NULL;
+       mono_sgen_free_internal (section, INTERNAL_MEM_GRAY_QUEUE);
 }
 
 /*
  * 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 below.
+ * for them in sgen-gc.h.
  */
 
-static inline void
-gray_object_enqueue (char *obj)
+void
+mono_sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj)
 {
        DEBUG (9, g_assert (obj));
-       if (G_UNLIKELY (!gray_queue_end || gray_queue_end->end == GRAY_QUEUE_SECTION_SIZE))
-               gray_object_alloc_queue_section ();
-       DEBUG (9, g_assert (gray_queue_end && gray_queue_end->end < GRAY_QUEUE_SECTION_SIZE));
-       gray_queue_end->objects [gray_queue_end->end++] = obj;
+       if (G_UNLIKELY (!queue->first || queue->first->end == SGEN_GRAY_QUEUE_SECTION_SIZE))
+               mono_sgen_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, ++gray_queue_balance);
+       DEBUG (9, ++queue->balance);
 }
 
-static inline char*
-gray_object_dequeue (void)
+char*
+mono_sgen_gray_object_dequeue (SgenGrayQueue *queue)
 {
        char *obj;
 
-       if (gray_object_queue_is_empty ())
+       if (mono_sgen_gray_object_queue_is_empty (queue))
                return NULL;
 
-       DEBUG (9, 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;
+       }
 
-       DEBUG (9, --gray_queue_balance);
+       DEBUG (9, --queue->balance);
 
        return obj;
 }
 
-#if MAX_DEBUG_LEVEL >= 9
-#define GRAY_OBJECT_ENQUEUE gray_object_enqueue
-#define GRAY_OBJECT_DEQUEUE(o) ((o) = gray_object_dequeue ())
-#else
-#define GRAY_OBJECT_ENQUEUE(o) do {                                    \
-               if (G_UNLIKELY (!gray_queue_end || gray_queue_end->end == GRAY_QUEUE_SECTION_SIZE)) \
-                       gray_object_alloc_queue_section ();             \
-               gray_queue_end->objects [gray_queue_end->end++] = (o);  \
-       } while (0)
-#define GRAY_OBJECT_DEQUEUE(o) do {                                    \
-               if (!gray_queue_end) {                                  \
-                       (o) = NULL;                                     \
-               } else {                                                \
-                       (o) = gray_queue_end->objects [--gray_queue_end->end]; \
-                       if (G_UNLIKELY (gray_queue_end->end == 0))      \
-                               gray_queue_end = gray_queue_end->prev;  \
-               }                                                       \
-       } while (0)
-#endif
+GrayQueueSection*
+mono_sgen_gray_object_dequeue_section (SgenGrayQueue *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)
+void
+mono_sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *section)
+{
+       section->next = queue->first;
+       queue->first = section;
+}
+
+void
+mono_sgen_gray_object_queue_init (SgenGrayQueue *queue)
 {
        GrayQueueSection *section, *next;
        int i;
 
-       g_assert (gray_object_queue_is_empty ());
-       g_assert (sizeof (GrayQueueSection) < MAX_FREELIST_SIZE);
-       DEBUG (9, g_assert (gray_queue_balance == 0));
+       g_assert (mono_sgen_gray_object_queue_is_empty (queue));
+       DEBUG (9, g_assert (queue->balance == 0));
 
        /* 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;
+               mono_sgen_gray_object_free_queue_section (next);
        }
 }
+
+void
+mono_sgen_gray_object_queue_init_with_alloc_prepare (SgenGrayQueue *queue, GrayQueueAllocPrepareFunc func, void *data)
+{
+       mono_sgen_gray_object_queue_init (queue);
+       queue->alloc_prepare_func = func;
+       queue->alloc_prepare_data = data;
+}
+
+#endif