[coop] New local handles implementation.
authorRodrigo Kumpera <kumpera@gmail.com>
Sat, 28 May 2016 01:03:56 +0000 (18:03 -0700)
committerRodrigo Kumpera <kumpera@gmail.com>
Fri, 3 Jun 2016 21:28:05 +0000 (14:28 -0700)
This is the initial code drop of a new handles implementation.

It differs from the previous one is a few ways:

- It keeps a separate stack of handles which is shared by all "arenas".
This eliminates malloc in the majority of the cases without the need for any tuning

- Custom gc scanning code for the handles stack.
The original implementation registered the chunks as a GC roots. Which is a terribly
slow operation as it takes the GC lock.

Instead of allocating a new handle arena for each icall, we compute a stack mark,
which is the position in the handles stack at icall entry. On exit, we simply restore that
position, which is just a couple of stores.

Since the stack is implemented using arraylets, addressed are stable in the face of
expansion.

Only the typed handles function/macros are in as having both typed and untyped handles
adds extra complexity for no clear value.

The macros only handle what was needed to port a sizeable chunk of locales.c.

This commit just sets the stage for the feature, there's quite some work left
before we can start using it, as it can be seen in the big TODO in handle.c

mono/metadata/handle.c
mono/metadata/handle.h
mono/metadata/sgen-mono.c
mono/unit-tests/test-mono-handle.c
mono/utils/mono-threads.h

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
index 99a0428290355f98fad465166ced168e0b8f1c84..3d48c0648580442e50dde4272fa6b130f434f60c 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/metadata/object.h>
 #include <mono/metadata/class.h>
-#include <mono/utils/mono-error.h>
+#include <mono/utils/mono-error-internals.h>
+#include <mono/utils/mono-threads.h>
 #include <mono/utils/checked-build.h>
 
 G_BEGIN_DECLS
 
-/*
- * DO NOT ACCESS DIRECTLY
- * USE mono_handle_obj BELOW TO ACCESS OBJ
- *
- * The field obj is not private as there is no way to do that
- * in C, but using a C++ template would simplify that a lot
- */
-typedef struct {
-       MonoObject *__private_obj;
-} MonoHandleStorage;
-
-typedef MonoHandleStorage* MonoHandle;
 
-typedef struct _MonoHandleArena MonoHandleArena;
+/*
+Handle stack.
 
-gsize
-mono_handle_arena_size (void);
+The handle stack is designed so it's efficient to pop a large amount of entries at once.
+The stack is made out of a series of fixed size segments.
 
-MonoHandle
-mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj);
+To do bulk operations you use a stack mark.
+       
+*/
 
-MonoHandle
-mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle);
+/*
+3 is the number of fields besides the data in the struct;
+128 words makes each chunk 512 or 1024 bytes each
+*/
+#define OBJECTS_PER_HANDLES_CHUNK (128 - 3)
 
-void
-mono_handle_arena_stack_push (MonoHandleArena **arena_stack, MonoHandleArena *arena);
+/*
+Whether this config needs stack watermark recording to know where to start scanning from.
+*/
+#ifdef HOST_WATCHOS
+#define MONO_NEEDS_STACK_WATERMARK 1
+#endif
 
-void
-mono_handle_arena_stack_pop (MonoHandleArena **arena_stack, MonoHandleArena *arena);
+typedef struct _HandleChunk HandleChunk;
 
-void
-mono_handle_arena_init (MonoHandleArena **arena_stack);
+struct _HandleChunk {
+       int size; //number of bytes
+       HandleChunk *prev, *next;
+       MonoObject *objects [OBJECTS_PER_HANDLES_CHUNK];
+};
 
-void
-mono_handle_arena_cleanup (MonoHandleArena **arena_stack);
+typedef struct {
+       HandleChunk *top; //alloc from here
+       HandleChunk *bottom; //scan from here
+} HandleStack;
 
-MonoHandleArena*
-mono_handle_arena_current (void);
+typedef struct {
+       int size;
+       HandleChunk *chunk;
+} HandleStackMark;
 
-MonoHandleArena**
-mono_handle_arena_current_addr (void);
+typedef void *MonoRawHandle;
 
-#define MONO_HANDLE_ARENA_PUSH()       \
-       do {    \
-               MonoHandleArena **__arena_stack = mono_handle_arena_current_addr ();    \
-               MonoHandleArena *__arena = (MonoHandleArena*) g_alloca (mono_handle_arena_size ());     \
-               mono_handle_arena_stack_push (__arena_stack, __arena)
+typedef void (*GcScanFunc) (gpointer*, gpointer);
 
-#define MONO_HANDLE_ARENA_POP()        \
-               mono_handle_arena_stack_pop (__arena_stack, __arena);   \
-       } while (0)
 
-#define MONO_HANDLE_ARENA_POP_RETURN_UNSAFE(handle,ret)        \
-               (ret) = (handle)->__private_obj;        \
-               mono_handle_arena_stack_pop (__arena_stack, __arena);   \
-       } while (0)
+MonoRawHandle mono_handle_new (MonoObject *object);
 
-#define MONO_HANDLE_ARENA_POP_RETURN(handle,ret_handle)        \
-               *((MonoHandle**)(&(ret_handle))) = mono_handle_elevate ((MonoHandle*)(handle)); \
-               mono_handle_arena_stack_pop(__arena_stack, __arena);    \
-       } while (0)
+void mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data);
+HandleStack* mono_handle_stack_alloc (void);
+void mono_handle_stack_free (HandleStack *handlestack);
+MonoRawHandle mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value);
+void mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name);
 
-static inline MonoHandle
-mono_handle_new (MonoObject *obj)
+static void
+mono_stack_mark_init (MonoThreadInfo *info, HandleStackMark *stackmark)
 {
-       return mono_handle_arena_new (mono_handle_arena_current (), obj);
+       HandleStack *handles = (HandleStack *)info->handle_stack;
+       stackmark->size = handles->top->size;
+       stackmark->chunk = handles->top;
 }
 
-static inline MonoHandle
-mono_handle_elevate (MonoHandle handle)
+static void
+mono_stack_mark_pop (MonoThreadInfo *info, HandleStackMark *stackmark)
 {
-       return mono_handle_arena_elevate (mono_handle_arena_current (), handle);
+       HandleStack *handles = (HandleStack *)info->handle_stack;
+       handles->top = stackmark->chunk;
+       handles->top->size = stackmark->size;
 }
 
-#ifndef ENABLE_CHECKED_BUILD
+/*
+Icall macros
+*/
+#define SETUP_ICALL_COMMON     \
+       do { \
+               MonoError error;        \
+               MonoThreadInfo *__info = mono_thread_info_current ();   \
+               error_init (&error);    \
 
-#define mono_handle_obj(handle) ((handle)->__private_obj)
+#define CLEAR_ICALL_COMMON     \
+       mono_error_set_pending_exception (&error);
 
-#define mono_handle_assign(handle,rawptr) do { (handle)->__private_obj = (rawptr); } while(0)
+#define SETUP_ICALL_FRAME      \
+       HandleStackMark __mark; \
+       mono_stack_mark_init (__info, &__mark);
 
-#else
+#define CLEAR_ICALL_FRAME      \
+       mono_stack_mark_record_size (__info, &__mark, __FUNCTION__);    \
+       mono_stack_mark_pop (__info, &__mark);
+
+#ifdef MONO_NEEDS_STACK_WATERMARK
 
-static inline void
-mono_handle_check_in_critical_section ()
+static void
+mono_thread_info_pop_stack_mark (MonoThreadInfo *info, void *old_mark)
 {
-       MONO_REQ_GC_CRITICAL;
+       info->stack_mark = old_mark;
 }
 
-#define mono_handle_obj(handle) (mono_handle_check_in_critical_section (), (handle)->__private_obj)
+static void*
+mono_thread_info_push_stack_mark (MonoThreadInfo *info, void *mark)
+{
+       void *old = info->stack_mark;
+       info->stack_mark = mark;
+       return old;
+}
 
-#define mono_handle_assign(handle,rawptr) do { mono_handle_check_in_critical_section (); (handle)->__private_obj = (rawptr); } while (0)
+#define SETUP_STACK_WATERMARK  \
+       int __dummy;    \
+       __builtin_unwind_init ();       \
+       void *__old_stack_mark = mono_thread_info_push_stack_mark (__info, &__dummy);
 
-#endif
+#define CLEAR_STACK_WATERMARK  \
+       mono_thread_info_pop_stack_mark (__info, __old_stack_mark);
 
-static inline MonoClass*
-mono_handle_class (MonoHandle handle)
-{
-       return mono_object_get_class (handle->__private_obj);
-}
+#else
+#define SETUP_STACK_WATERMARK
+#define CLEAR_STACK_WATERMARK
+#endif
 
-static inline MonoDomain*
-mono_handle_domain (MonoHandle handle)
-{
-       return mono_object_get_domain (handle->__private_obj);
-}
+#define ICALL_ENTRY()  \
+       SETUP_ICALL_COMMON      \
+       SETUP_ICALL_FRAME       \
+       SETUP_STACK_WATERMARK
 
-#define mono_handle_obj_is_null(handle) ((handle)->__private_obj == NULL)
+#define ICALL_RETURN() \
+       do {    \
+               CLEAR_STACK_WATERMARK   \
+               CLEAR_ICALL_COMMON      \
+               CLEAR_ICALL_FRAME       \
+               return; \
+       } while (0); } while (0)
 
-#define MONO_HANDLE_TYPE_DECL(type)      typedef struct { type *__private_obj; } type ## HandleStorage ; \
-       typedef type ## HandleStorage * type ## Handle
-#define MONO_HANDLE_TYPE(type)           type ## Handle
-#define MONO_HANDLE_NEW(type,obj)        ((type ## Handle) mono_handle_new ((MonoObject*) (obj)))
-#define MONO_HANDLE_ELEVATE(type,handle) ((type ## Handle) mono_handle_elevate ((MonoObject*) (handle)->__private_obj))
+#define ICALL_RETURN_VAL(VAL)  \
+       do {    \
+               CLEAR_STACK_WATERMARK   \
+               CLEAR_ICALL_COMMON      \
+               CLEAR_ICALL_FRAME       \
+               return VAL;     \
+       } while (0); } while (0)
 
-#define MONO_HANDLE_ASSIGN(handle,rawptr)      \
+#define ICALL_RETURN_OBJ(HANDLE)       \
        do {    \
-               mono_handle_assign ((handle), (rawptr));        \
-       } while (0)
+               CLEAR_STACK_WATERMARK   \
+               CLEAR_ICALL_COMMON      \
+               void* __ret = MONO_HANDLE_RAW (HANDLE); \
+               CLEAR_ICALL_FRAME       \
+               return __ret;   \
+       } while (0); } while (0)
 
-#define MONO_HANDLE_SETREF(handle,fieldname,value)                     \
-       do {                                                            \
-               MonoHandle __value = (MonoHandle) (value);              \
-               MONO_PREPARE_GC_CRITICAL_REGION;                                        \
-               MONO_OBJECT_SETREF (mono_handle_obj ((handle)), fieldname, mono_handle_obj (__value)); \
-               MONO_FINISH_GC_CRITICAL_REGION;                                 \
-       } while (0)
+/*
+Handle macros/functions
+*/
 
-#define MONO_HANDLE_SETREF_NULL(handle,fieldname)                      \
-       do {                                                            \
-               MONO_PREPARE_GC_CRITICAL_REGION;                        \
-               MONO_OBJECT_SETREF (mono_handle_obj ((handle)), fieldname, NULL); \
-               MONO_FINISH_GC_CRITICAL_REGION;                         \
-       } while (0)
+#ifdef ENABLE_CHECKED_BUILD
+void mono_handle_verify (MonoRawHandle handle);
+#define HANDLE_INVARIANTS(H) mono_handle_verify((void*)(H).__obj)
+#else
+#define HANDLE_INVARIANTS(H) (0)
+#endif
 
+#define TYPED_HANDLE_NAME(TYPE) TYPE ## Handle
+#define TYPED_HANDLE_DECL(TYPE) typedef struct { TYPE **__obj; } TYPED_HANDLE_NAME (TYPE) ;
 
-#define MONO_HANDLE_SET(handle,fieldname,value)        \
-       do {    \
-               MONO_PREPARE_GC_CRITICAL_REGION;        \
-               mono_handle_obj ((handle))->fieldname = (value);        \
-               MONO_FINISH_GC_CRITICAL_REGION; \
-       } while (0)
+#define MONO_HANDLE_INIT { (void*)mono_null_value_handle.__obj }
+#define NULL_HANDLE mono_null_value_handle
 
-#define MONO_HANDLE_ARRAY_SETREF(handle,index,value)                   \
-       do {                                                            \
-               MonoHandle __value = (MonoHandle) (value);              \
-               MONO_PREPARE_GC_CRITICAL_REGION;                                        \
-               mono_array_setref (mono_handle_obj ((handle)), (index), mono_handle_obj (__value)); \
-               MONO_FINISH_GC_CRITICAL_REGION;                                 \
-       } while (0)
+//XXX add functions to get/set raw, set field, set field to null, set array, set array to null
+#define MONO_HANDLE_RAW(HANDLE) (HANDLE_INVARIANTS (HANDLE), (*(HANDLE).__obj))
+#define MONO_HANDLE_DCL(TYPE, NAME) TYPED_HANDLE_NAME(TYPE) NAME = { mono_handle_new ((MonoObject*)(NAME ## _raw)) }
+#define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE)){ mono_handle_new ((MonoObject*)(VALUE)) }
+#define MONO_HANDLE_CAST(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE)){ (TYPE**)((VALUE).__obj) }
 
-#define MONO_HANDLE_ARRAY_SETREF_NULL(handle,index)                    \
-       do {                                                            \
-               MONO_PREPARE_GC_CRITICAL_REGION;                        \
-               mono_array_setref (mono_handle_obj ((handle)), (index), NULL); \
-               MONO_FINISH_GC_CRITICAL_REGION;                         \
+/*
+WARNING WARNING WARNING
+
+The following functions require a particular evaluation ordering to ensure correctness.
+We must not have exposed handles while any sort of evaluation is happening as that very evaluation might trigger
+a safepoint and break us.
+
+This is why we evaluate index and value before any call to MONO_HANDLE_RAW or other functions that deal with naked objects.
+*/
+#define MONO_HANDLE_SETRAW(HANDLE, FIELD, VALUE) do {  \
+               MonoObject *__val = (MonoObject*)(VALUE);       \
+               MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, __val);    \
+       } while (0);
+
+#define MONO_HANDLE_SET(HANDLE, FIELD, VALUE) do {     \
+               MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE);  \
+               MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, MONO_HANDLE_RAW (__val));  \
+       } while (0);
+
+/* VS doesn't support typeof :( :( :( */
+#define MONO_HANDLE_SETVAL(HANDLE, FIELD, TYPE, VALUE) do {    \
+               TYPE __val = (VALUE);   \
+               MONO_HANDLE_RAW (HANDLE)->FIELD = __val;        \
+        } while (0)
+
+#define MONO_HANDLE_ARRAY_SETREF(HANDLE, IDX, VALUE) do {      \
+               int __idx = (IDX);      \
+               MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE);          \
+               mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, MONO_HANDLE_RAW (__val));      \
        } while (0)
-       
 
-#define MONO_HANDLE_ARRAY_SET(handle,type,index,value) \
-       do {    \
-               MONO_PREPARE_GC_CRITICAL_REGION;        \
-               mono_array_set (mono_handle_obj ((handle)), type, (index), (value));    \
-               MONO_FINISH_GC_CRITICAL_REGION; \
+#define MONO_HANDLE_ARRAY_SETRAW(HANDLE, IDX, VALUE) do {      \
+               int __idx = (IDX);      \
+               MonoObject *__val = (MonoObject*)(VALUE);       \
+               mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, __val);        \
        } while (0)
 
 
+/* Baked typed handles we all want */
+TYPED_HANDLE_DECL (MonoString)
+TYPED_HANDLE_DECL (MonoArray)
+TYPED_HANDLE_DECL (MonoObject)
 
+/*
+This is the constant for a handle that points nowhere.
+Init values to it.
+*/
+extern const MonoObjectHandle mono_null_value_handle;
 
-/* Some common handle types */
 
-MONO_HANDLE_TYPE_DECL (MonoArray);
-MONO_HANDLE_TYPE_DECL (MonoString);
+//FIXME this should go somewhere else
+MonoStringHandle mono_string_new_handle (MonoDomain *domain, const char *data);
+MonoArrayHandle mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error);
 
 G_END_DECLS
 
index 339a4de7e4057eff833cd9db1a9de4b605a9ba35..eb22e9bb66ab1485fe7de68e27e2cc624a63514a 100644 (file)
@@ -2243,6 +2243,8 @@ sgen_client_thread_register (SgenThreadInfo* info, void *stack_bottom_fallback)
        binary_protocol_thread_register ((gpointer)mono_thread_info_get_tid (info));
 
        SGEN_LOG (3, "registered thread %p (%p) stack end %p", info, (gpointer)mono_thread_info_get_tid (info), info->client_info.stack_end);
+
+       info->client_info.info.handle_stack = mono_handle_stack_alloc ();
 }
 
 void
@@ -2268,6 +2270,10 @@ sgen_client_thread_unregister (SgenThreadInfo *p)
 
        binary_protocol_thread_unregister ((gpointer)tid);
        SGEN_LOG (3, "unregister thread %p (%p)", p, (gpointer)tid);
+
+       HandleStack *handles = (HandleStack*) p->client_info.info.handle_stack;
+       p->client_info.info.handle_stack = NULL;
+       mono_handle_stack_free (handles);
 }
 
 void
@@ -2295,8 +2301,6 @@ thread_in_critical_region (SgenThreadInfo *info)
 static void
 sgen_thread_attach (SgenThreadInfo *info)
 {
-       mono_handle_arena_init ((MonoHandleArena**) &info->client_info.info.handle_arena);
-
        if (mono_gc_get_gc_callbacks ()->thread_attach_func && !info->client_info.runtime_data)
                info->client_info.runtime_data = mono_gc_get_gc_callbacks ()->thread_attach_func ();
 }
@@ -2312,8 +2316,6 @@ sgen_thread_detach (SgenThreadInfo *p)
         */
        if (mono_domain_get ())
                mono_thread_detach_internal (mono_thread_internal_current ());
-
-       mono_handle_arena_cleanup ((MonoHandleArena**) &p->client_info.info.handle_arena);
 }
 
 gboolean
@@ -2402,6 +2404,7 @@ sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean p
                                fprintf (stderr, "Precise stack mark not supported - disabling.\n");
                                conservative_stack_mark = TRUE;
                        }
+                       //FIXME we should eventually use the new stack_mark from coop
                        sgen_conservatively_pin_objects_from ((void **)aligned_stack_start, (void **)info->client_info.stack_end, start_nursery, end_nursery, PIN_TYPE_STACK);
                }
 
@@ -2412,6 +2415,7 @@ sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean p
                        {
                                // This is used on Coop GC for platforms where we cannot get the data for individual registers.
                                // We force a spill of all registers into the stack and pass a chunk of data into sgen.
+                               //FIXME under coop, for now, what we need to ensure is that we scan any extra memory from info->client_info.stack_end to stack_mark
                                MonoThreadUnwindState *state = &info->client_info.info.thread_saved_state [SELF_SUSPEND_STATE_INDEX];
                                if (state && state->gc_stackdata) {
                                        sgen_conservatively_pin_objects_from ((void **)state->gc_stackdata, (void**)((char*)state->gc_stackdata + state->gc_stackdata_size),
@@ -2419,6 +2423,9 @@ sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean p
                                }
                        }
                }
+               if (precise && info->client_info.info.handle_stack) {
+                       mono_handle_stack_scan ((HandleStack*)info->client_info.info.handle_stack, (GcScanFunc)ctx.ops->copy_or_mark_object, ctx.queue);
+               }
        } FOREACH_THREAD_END
 }
 
index 3438039a4b0cb91900fa6e057be353b38b47e04b..95ebae349c29aa1cbd562a8642ec09a17299c5b1 100644 (file)
 static void
 test2_arena_push_pop ()
 {
-       MonoHandleArena *top = NULL;
-
-       MonoHandleArena *new_arena1 = g_malloc0 (mono_handle_arena_size ());
-       mono_handle_arena_stack_push (&top, new_arena1);
-
-       MonoHandleArena *new_arena2 = g_malloc0 (mono_handle_arena_size ());
-
-       mono_handle_arena_stack_push (&top, new_arena2);
-
-       g_assert (top == new_arena2);
-
-       mono_handle_arena_stack_pop (&top, new_arena2);
-
-       g_free (new_arena2);
-
-       g_assert (top == new_arena1);
-
-       mono_handle_arena_stack_pop (&top, new_arena1);
-
-       g_assert (top == NULL);
-       
-       g_free (new_arena1);
+       HandleStack *h = mono_handle_stack_alloc ();
+       mono_handle_stack_free (h);
 }
 
 
index da88f34e35b6ae32d1fc30bdfacf06d1406d5709..7f304295fcd4c42e86fb15374e443921c29381b4 100644 (file)
@@ -237,8 +237,11 @@ typedef struct {
 
        MonoThreadInfoInterruptToken *interrupt_token;
 
-       /* MonoHandleArena for coop handles */
-       gpointer handle_arena;
+       /* HandleStack for coop handles */
+       gpointer handle_stack;
+
+       /* Stack mark for targets that explicitly require one */
+       gpointer stack_mark;
 } MonoThreadInfo;
 
 typedef struct {