Merge pull request #3142 from henricm/fix-for-win-mono_string_to_utf8
[mono.git] / mono / metadata / handle.c
index 6c266259508ae6f251856794587f9967db5fd7b1..4b4239eb66f7cfbd3b08ac9da26439b27bf64993 100644 (file)
@@ -3,8 +3,10 @@
  *
  * Authors:
  *  - Ludovic Henry <ludovic@xamarin.com>
+ *  - Aleksey Klieger <aleksey.klieger@xamarin.com>
+ *  - Rodrigo Kumpera <kumpera@xamarin.com>
  *
- * Copyright 2015 Xamarin, Inc. (www.xamarin.com)
+ * Copyright 2016 Dot net foundation.
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include <mono/utils/atomic.h>
 #include <mono/utils/mono-lazy-init.h>
 #include <mono/utils/mono-threads.h>
+/* TODO (missing pieces)
 
-#define HANDLES_PER_CHUNK (16 - 2)
+Add counters for:
+       number of stack marks
+       stack marks per icall
+       mix/max/avg size of stack marks
+       handle stack wastage
 
-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];
-};
+Actually do something in mono_handle_verify
 
-struct _MonoHandleArena {
-       MonoHandleArenaChunk *chunk;
-       MonoHandleArena *prev;
-};
+Shrink the handles stack in mono_handle_stack_scan
+Properly report it to the profiler.
+Add a boehm implementation
 
-static mono_lazy_init_t arena_status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
+TODO (things to explore):
 
-static MonoGCDescriptor arena_desc = MONO_GC_DESCRIPTOR_NULL;
+There's no convenient way to wrap the object allocation function.
+Right now we do this:
+       MonoCultureInfoHandle culture = MONO_HANDLE_NEW (MonoCultureInfo, mono_object_new_checked (domain, klass, &error));
 
-static MonoHandleArenaChunk *chunk_free_list = NULL;
+Maybe what we need is a round of cleanup around all exposed types in the runtime to unify all helpers under the same hoof.
+Combine: MonoDefaults, GENERATE_GET_CLASS_WITH_CACHE, TYPED_HANDLE_DECL and friends.
+       This would solve the age old issue of making it clear which types are optional and tell that to the linker.
+       We could then generate neat type safe wrappers.
+*/
 
-static inline MonoHandleArenaChunk*
-chunk_alloc (void)
-{
-       MonoHandleArenaChunk *old, *new;
-
-       do {
-               old = chunk_free_list;
-               if (!old) {
-                       MonoHandleArenaChunk *chunk;
-
-                       chunk = g_malloc0 (sizeof (MonoHandleArenaChunk));
-                       g_assert (chunk);
+const MonoObject *null_cell = { NULL };
+const MonoObjectHandle mono_null_value_handle = { (MonoObject**)&null_cell };
 
-                       return chunk;
-               }
-
-               new = old->next;
-       } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, new, old) != old);
-
-       memset (old, 0, sizeof (MonoHandleArenaChunk));
-       return old;
-}
+#define THIS_IS_AN_OK_NUMBER_OF_HANDLES 100
 
-static inline void
-chunk_free (MonoHandleArenaChunk *chunk)
+/* Actual handles implementation */
+MonoRawHandle
+mono_handle_new (MonoObject *object)
 {
-       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;
+       MonoThreadInfo *info = mono_thread_info_current ();
+       HandleStack *handles = (HandleStack *)info->handle_stack;
+       HandleChunk *top = handles->top;
+
+retry:
+       if (G_LIKELY (top->size < OBJECTS_PER_HANDLES_CHUNK)) {
+               MonoObject **h = &top->objects [top->size++];
+               *h = object;
+               return h;
        }
-}
-
-static MonoHandle
-handle_new (MonoHandleArena *arena, MonoObject *obj)
-{
-       MonoHandleArenaChunk *chunk;
-
-       g_assert (arena->chunk);
-
-       chunk = arena->chunk;
-
-       if (chunk->handles_size < HANDLES_PER_CHUNK) {
-               chunk->handles [chunk->handles_size].__private_obj = obj;
-               chunk->handles_size += 1;
-
-               return &chunk->handles [chunk->handles_size - 1];
-       } else {
-
-               MonoHandleArenaChunk *new_chunk = chunk_alloc ();
-               new_chunk->next = chunk;
-               arena->chunk = chunk = new_chunk;
-
-               chunk->handles [0].__private_obj = obj;
-               chunk->handles_size = 1;
-
-               return &chunk->handles [0];
+       if (G_LIKELY (top->next)) {
+               top = top->next;
+               top->size = 0;
+               handles->top = top;
+               goto retry;
        }
+       HandleChunk *new_chunk = g_new (HandleChunk, 1);
+       new_chunk->size = 0;
+       new_chunk->prev = top;
+       new_chunk->next = NULL;
+       top->next = new_chunk;
+       handles->top = new_chunk;
+       goto retry;
 }
 
-MonoHandle
-mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj)
-{
-       g_assert (arena);
-       return handle_new (arena, obj);
-}
-
-/*
- * Elevate the handle to the parent arena
- */
-MonoHandle
-mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle)
-{
-       g_assert (handle);
-       g_assert (arena);
-       g_assert (arena->prev);
 
-       return handle_new (arena->prev, handle->__private_obj);
-}
 
-gsize
-mono_handle_arena_size (void)
+HandleStack*
+mono_handle_stack_alloc (void)
 {
-       return sizeof (MonoHandleArena) + sizeof (MonoHandleArenaChunk);
+       HandleStack *stack = g_new (HandleStack, 1);
+       HandleChunk *chunk = g_new (HandleChunk, 1);
+
+       stack->top = stack->bottom = chunk;
+       chunk->size = 0;
+       chunk->prev = chunk->next = NULL;
+       return stack;
 }
 
 void
-mono_handle_arena_stack_push(MonoHandleArena **arena_stack, MonoHandleArena *arena)
+mono_handle_stack_free (HandleStack *stack)
 {
-       g_assert (arena_stack);
-       g_assert (arena);
-
-       arena->prev = *arena_stack;
-       arena->chunk = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
-
-       arena->chunk->next = NULL;
-       arena->chunk->handles_size = 0;
-       memset (&arena->chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
-
-       *arena_stack = arena;
+       if (!stack)
+               return;
+       HandleChunk *c = stack->bottom;
+       while (c) {
+               HandleChunk *next = c->next;
+               g_free (c);
+               c = next;
+       }
+       g_free (c);
 }
 
 void
-mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *arena)
+mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data)
 {
-       MonoHandleArenaChunk *chunk, *next;
+       HandleChunk *cur = stack->bottom;
+       HandleChunk *last = stack->top;
 
-       g_assert (arena);
-       g_assert (arena->chunk);
-       g_assert (arena_stack);
-
-       *arena_stack = arena->prev;
+       if (!cur)
+               return;
 
-       for (chunk = arena->chunk; chunk; chunk = next) {
-               next = chunk->next;
-               memset (&chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
-               if (next != NULL)
-                       chunk_free (chunk);
+       while (cur) {
+               int i;
+               for (i = 0; i < cur->size; ++i)
+                       func ((gpointer*)&cur->objects [i], gc_data);
+               if (cur == last)
+                       break;
+               cur = cur->next;
        }
 }
 
-static void
-arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
+void
+mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name)
 {
-       MonoHandleArena *arena;
-       MonoHandleArenaChunk *chunk;
-       int i;
-
-       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].__private_obj != NULL)
-                                       mark_func (&chunk->handles [i].__private_obj, gc_data);
-                       }
-               }
+       HandleStack *handles = (HandleStack *)info->handle_stack;
+       HandleChunk *cur = stackmark->chunk;
+       int size = -stackmark->size; //discard the starting point of the stack
+       while (cur) {
+               size += cur->size;
+               if (cur == handles->top)
+                       break;
+               cur = cur->next;
        }
-}
 
-static void
-initialize (void)
-{
-       arena_desc = mono_gc_make_root_descr_user (arena_scan);
+       if (size > THIS_IS_AN_OK_NUMBER_OF_HANDLES)
+               printf ("%s USED %d handles\n", func_name, size);
 }
 
-void
-mono_handle_arena_init (MonoHandleArena **arena_stack)
+/*
+ * Pop the stack until @stackmark and make @value the top value.
+ *
+ * @return the new handle for what @value points to 
+ */
+MonoRawHandle
+mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value)
 {
-       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");
+       g_error ("impl me");
 }
 
-void
-mono_handle_arena_cleanup (MonoHandleArena **arena_stack)
+/* Temporary place for some of the handle enabled wrapper functions*/
+
+MonoStringHandle
+mono_string_new_handle (MonoDomain *domain, const char *data)
 {
-       mono_gc_deregister_root ((char*) arena_stack);
+       return MONO_HANDLE_NEW (MonoString, mono_string_new (domain, data));
 }
 
-MonoHandleArena*
-mono_handle_arena_current (void)
+MonoArrayHandle
+mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
 {
-       return (MonoHandleArena*) mono_thread_info_current ()->handle_arena;
+       return MONO_HANDLE_NEW (MonoArray, mono_array_new_checked (domain, eclass, n, error));
 }
 
-MonoHandleArena**
-mono_handle_arena_current_addr (void)
+#ifdef ENABLE_CHECKED_BUILD
+/* Checked build helpers */
+void
+mono_handle_verify (MonoRawHandle raw_handle)
 {
-       return (MonoHandleArena**) &mono_thread_info_current ()->handle_arena;
+       
 }
+#endif