Merge pull request #2802 from BrzVlad/feature-evacuation-opt2
[mono.git] / mono / metadata / handle.c
index ca66442c4032f3e30c1d332351e6aa6f9ca865f9..6c266259508ae6f251856794587f9967db5fd7b1 100644 (file)
@@ -5,6 +5,7 @@
  *  - Ludovic Henry <ludovic@xamarin.com>
  *
  * Copyright 2015 Xamarin, Inc. (www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include <config.h>
 #include <mono/metadata/gc-internals.h>
 #include <mono/utils/atomic.h>
 #include <mono/utils/mono-lazy-init.h>
+#include <mono/utils/mono-threads.h>
 
 #define HANDLES_PER_CHUNK (16 - 2)
 
 typedef struct _MonoHandleArenaChunk MonoHandleArenaChunk;
 struct _MonoHandleArenaChunk {
+       /* if next is NULL, this is the first chunk.
+        *
+        * The first chunk is special - it was allocated together with
+        * its owning arena and must not be deallocated unless the
+        * arena is being deallocated.  N.B: Arenas are
+        * stack-allocated.
+        */
        MonoHandleArenaChunk *next;
        gsize handles_size;
        MonoHandleStorage handles [HANDLES_PER_CHUNK];
@@ -27,15 +36,12 @@ struct _MonoHandleArenaChunk {
 
 struct _MonoHandleArena {
        MonoHandleArenaChunk *chunk;
-       MonoHandleArenaChunk *chunk_last;
        MonoHandleArena *prev;
 };
 
 static mono_lazy_init_t arena_status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
 
-#ifdef HAVE_SGEN_GC
 static MonoGCDescriptor arena_desc = MONO_GC_DESCRIPTOR_NULL;
-#endif
 
 static MonoHandleArenaChunk *chunk_free_list = NULL;
 
@@ -65,9 +71,16 @@ chunk_alloc (void)
 static inline void
 chunk_free (MonoHandleArenaChunk *chunk)
 {
-       do {
-               chunk->next = chunk_free_list;
-       } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
+       if (chunk == NULL)
+               return;
+       while (chunk->next != NULL) {
+               MonoHandleArenaChunk *next = chunk->next;
+               chunk->next = NULL;
+               do {
+                       chunk->next = chunk_free_list;
+               } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
+               chunk = next;
+       }
 }
 
 static MonoHandle
@@ -76,25 +89,25 @@ handle_new (MonoHandleArena *arena, MonoObject *obj)
        MonoHandleArenaChunk *chunk;
 
        g_assert (arena->chunk);
-       g_assert (arena->chunk_last);
 
-       chunk = arena->chunk_last;
+       chunk = arena->chunk;
 
        if (chunk->handles_size < HANDLES_PER_CHUNK) {
-               chunk->handles [chunk->handles_size].obj = obj;
+               chunk->handles [chunk->handles_size].__private_obj = obj;
                chunk->handles_size += 1;
 
                return &chunk->handles [chunk->handles_size - 1];
-       }
+       } else {
 
-       chunk = chunk->next = chunk_alloc ();
+               MonoHandleArenaChunk *new_chunk = chunk_alloc ();
+               new_chunk->next = chunk;
+               arena->chunk = chunk = new_chunk;
 
-       chunk->handles [0].obj = obj;
-       chunk->handles_size = 1;
+               chunk->handles [0].__private_obj = obj;
+               chunk->handles_size = 1;
 
-       arena->chunk_last = chunk;
-
-       return &chunk->handles [0];
+               return &chunk->handles [0];
+       }
 }
 
 MonoHandle
@@ -114,7 +127,7 @@ mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle)
        g_assert (arena);
        g_assert (arena->prev);
 
-       return handle_new (arena->prev, handle->obj);
+       return handle_new (arena->prev, handle->__private_obj);
 }
 
 gsize
@@ -130,7 +143,7 @@ mono_handle_arena_stack_push(MonoHandleArena **arena_stack, MonoHandleArena *are
        g_assert (arena);
 
        arena->prev = *arena_stack;
-       arena->chunk = arena->chunk_last = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
+       arena->chunk = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
 
        arena->chunk->next = NULL;
        arena->chunk->handles_size = 0;
@@ -146,7 +159,6 @@ mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *aren
 
        g_assert (arena);
        g_assert (arena->chunk);
-       g_assert (arena->chunk_last);
        g_assert (arena_stack);
 
        *arena_stack = arena->prev;
@@ -154,7 +166,7 @@ mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *aren
        for (chunk = arena->chunk; chunk; chunk = next) {
                next = chunk->next;
                memset (&chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
-               if (chunk != arena->chunk)
+               if (next != NULL)
                        chunk_free (chunk);
        }
 }
@@ -169,8 +181,8 @@ arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
        for (arena = *(MonoHandleArena**) addr; arena; arena = arena->prev) {
                for (chunk = arena->chunk; chunk; chunk = chunk->next) {
                        for (i = 0; i < chunk->handles_size; ++i) {
-                               if (chunk->handles [i].obj != NULL)
-                                       mark_func (&chunk->handles [i].obj, gc_data);
+                               if (chunk->handles [i].__private_obj != NULL)
+                                       mark_func (&chunk->handles [i].__private_obj, gc_data);
                        }
                }
        }
@@ -179,36 +191,30 @@ arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
 static void
 initialize (void)
 {
-#ifdef HAVE_SGEN_GC
        arena_desc = mono_gc_make_root_descr_user (arena_scan);
-#endif
 }
 
 void
-mono_handle_arena_initialize (MonoHandleArena **arena_stack)
+mono_handle_arena_init (MonoHandleArena **arena_stack)
 {
-#ifdef HAVE_SGEN_GC
        mono_lazy_initialize (&arena_status, initialize);
        mono_gc_register_root ((char*) arena_stack, sizeof (MonoHandleArena*), arena_desc, MONO_ROOT_SOURCE_HANDLE, "runtime threads handle arena");
-#endif
 }
 
 void
-mono_handle_arena_deinitialize (MonoHandleArena **arena_stack)
+mono_handle_arena_cleanup (MonoHandleArena **arena_stack)
 {
-#ifdef HAVE_SGEN_GC
        mono_gc_deregister_root ((char*) arena_stack);
-#endif
 }
 
 MonoHandleArena*
 mono_handle_arena_current (void)
 {
-       g_assert_not_reached ();
+       return (MonoHandleArena*) mono_thread_info_current ()->handle_arena;
 }
 
 MonoHandleArena**
 mono_handle_arena_current_addr (void)
 {
-       g_assert_not_reached ();
+       return (MonoHandleArena**) &mono_thread_info_current ()->handle_arena;
 }