abi-details.h \
metadata-cross-helpers.c \
seq-points-data.h \
- seq-points-data.c
+ seq-points-data.c \
+ handle.c \
+ handle.h \
+ handle-private.h
# These source files have compile time dependencies on GC code
--- /dev/null
+#ifndef __MONO_HANDLE_PRIVATE_H__
+#define __MONO_HANDLE_PRIVATE_H__
+
+#include <mono/metadata/handle.h>
+
+MonoHandle
+mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj);
+
+MonoHandle
+mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle);
+
+void
+mono_handle_arena_stack_push (MonoHandleArena **arena_stack, MonoHandleArena *arena, gsize nb_handles);
+
+void
+mono_handle_arena_stack_pop (MonoHandleArena **arena_stack, MonoHandleArena *arena, gsize nb_handles);
+
+void
+mono_handle_arena_initialize (MonoHandleArena **arena_stack);
+
+void
+mono_handle_arena_deinitialize (MonoHandleArena **arena_stack);
+
+#endif/*__MONO_HANDLE_PRIVATE_H__*/
--- /dev/null
+/*
+ * handle.c: Handle to object in native code
+ *
+ * Authors:
+ * - Ludovic Henry <ludovic@xamarin.com>
+ *
+ * Copyright 2015 Xamarin, Inc. (www.xamarin.com)
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include <mono/metadata/handle.h>
+#include <mono/metadata/handle-private.h>
+#include <mono/metadata/object-internals.h>
+#include <mono/metadata/gc-internals.h>
+#include <mono/utils/atomic.h>
+#include <mono/utils/mono-lazy-init.h>
+
+#define HANDLES_PER_CHUNK (16 - 3)
+
+typedef struct _MonoHandleArenaChunk MonoHandleArenaChunk;
+struct _MonoHandleArenaChunk {
+ MonoHandleArenaChunk *next;
+ gsize handles_capacity;
+ gsize handles_size;
+ MonoHandleStorage handles [MONO_ZERO_LEN_ARRAY];
+};
+
+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;
+
+static inline MonoHandleArenaChunk*
+chunk_alloc (void)
+{
+ MonoHandleArenaChunk *old, *new;
+
+ do {
+ old = chunk_free_list;
+ if (!old) {
+ MonoHandleArenaChunk *chunk;
+
+ chunk = g_malloc0 (sizeof (MonoHandleArenaChunk) + sizeof (MonoHandleStorage) * (HANDLES_PER_CHUNK - MONO_ZERO_LEN_ARRAY));
+ chunk->handles_capacity = HANDLES_PER_CHUNK;
+
+ return chunk;
+ }
+
+ new = old->next;
+ } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, new, old) != old);
+
+ memset (old, 0, sizeof (MonoHandleArenaChunk));
+ return old;
+}
+
+static inline void
+chunk_free (MonoHandleArenaChunk *chunk)
+{
+ do {
+ chunk->next = chunk_free_list;
+ } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
+}
+
+static MonoHandle
+handle_new (MonoHandleArena *arena, MonoObject *obj)
+{
+ MonoHandleArenaChunk *chunk;
+
+ g_assert (arena->chunk);
+ g_assert (arena->chunk_last);
+
+ chunk = arena->chunk_last;
+
+ if (chunk->handles_size < chunk->handles_capacity) {
+ chunk->handles [chunk->handles_size].obj = obj;
+ chunk->handles_size += 1;
+
+ return &chunk->handles [chunk->handles_size - 1];
+ }
+
+ chunk = chunk->next = chunk_alloc ();
+
+ chunk->handles [0].obj = obj;
+ chunk->handles_size = 1;
+
+ arena->chunk_last = chunk;
+
+ return &chunk->handles [0];
+}
+
+MonoHandle
+mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj)
+{
+ g_assert (arena);
+ return handle_new (arena, obj);
+}
+
+MonoHandle
+mono_handle_new (MonoObject *obj)
+{
+ /* TODO: finish implementation by placing an arena somewhere
+ * in the current thread */
+ g_assert_not_reached ();
+ MonoHandleArena *arena = NULL;
+ return mono_handle_arena_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->obj);
+}
+
+MonoHandle
+mono_handle_elevate (MonoHandle handle)
+{
+ /* TODO: finish implementation by placing an arena somewhere
+ * in the current thread */
+ g_assert_not_reached ();
+ MonoHandleArena *arena = NULL;
+ return mono_handle_arena_elevate (arena, handle);
+}
+
+gsize
+mono_handle_arena_size (gsize nb_handles)
+{
+ g_assert (nb_handles > 0);
+ return sizeof (MonoHandleArena) + sizeof (MonoHandleArenaChunk) + sizeof (MonoHandle) * (MAX (nb_handles, HANDLES_PER_CHUNK) - MONO_ZERO_LEN_ARRAY);
+}
+
+void
+mono_handle_arena_stack_push(MonoHandleArena **arena_stack, MonoHandleArena *arena, gsize nb_handles)
+{
+ g_assert (arena_stack);
+ g_assert (arena);
+
+ arena->prev = *arena_stack;
+ arena->chunk = arena->chunk_last = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
+
+ arena->chunk->next = NULL;
+ arena->chunk->handles_capacity = MAX (nb_handles, HANDLES_PER_CHUNK);
+ arena->chunk->handles_size = 0;
+ memset (&arena->chunk->handles [0], 0, sizeof (MonoHandle) * arena->chunk->handles_capacity);
+
+ *arena_stack = arena;
+}
+
+void
+mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *arena, gsize nb_handles)
+{
+ MonoHandleArenaChunk *chunk, *next;
+
+ g_assert (arena);
+ g_assert (arena->chunk);
+ g_assert (arena->chunk_last);
+ g_assert (arena_stack);
+
+ *arena_stack = arena->prev;
+
+ for (chunk = arena->chunk; chunk; chunk = next) {
+ next = chunk->next;
+ memset (&chunk->handles [0], 0, sizeof (MonoHandle) * chunk->handles_capacity);
+ if (chunk != arena->chunk)
+ chunk_free (chunk);
+ }
+}
+
+static void
+arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
+{
+ 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].obj != NULL)
+ mark_func (&chunk->handles [i].obj, 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)
+{
+#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)
+{
+#ifdef HAVE_SGEN_GC
+ mono_gc_deregister_root ((char*) arena_stack);
+#endif
+}
+
--- /dev/null
+/*
+ * handle.h: Handle to object in native code
+ *
+ * Authors:
+ * - Ludovic Henry <ludovic@xamarin.com>
+ *
+ * Copyright 2015 Xamarin, Inc. (www.xamarin.com)
+ */
+
+#ifndef __MONO_HANDLE_H__
+#define __MONO_HANDLE_H__
+
+#include <config.h>
+#include <glib.h>
+
+#include "object.h"
+#include "class.h"
+#include "class-internals.h"
+#include "threads-types.h"
+
+#include "mono/utils/mono-threads-coop.h"
+
+G_BEGIN_DECLS
+
+typedef struct _MonoHandleStorage MonoHandleStorage;
+typedef MonoHandleStorage* MonoHandle;
+
+/*
+ * 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
+ */
+struct _MonoHandleStorage {
+ MonoObject *obj;
+};
+
+#ifndef CHECKED_BUILD
+
+#define mono_handle_obj(handle) ((handle)->obj)
+
+#define mono_handle_assign(handle,rawptr) do { (handle)->obj = (rawptr); } while(0)
+
+#else
+
+static inline void
+mono_handle_check_in_critical_section (const gchar* file, const gint lineno)
+{
+ MonoThreadInfo *info = (MonoThreadInfo*) mono_thread_info_current_unchecked ();
+ if (info && !info->inside_critical_region)
+ g_error ("Assertion at %s:%d: mono_handle_check_in_critical_section failed", file, lineno);
+}
+
+#define mono_handle_obj(handle) (mono_handle_check_in_critical_section (__FILE__, __LINE__), (handle)->obj)
+
+#define mono_handle_assign(handle,rawptr) do { mono_handle_check_in_critical_section (__FILE__, __LINE__); (handle)->obj = (rawptr); } while (0)
+
+#endif
+
+static inline MonoClass*
+mono_handle_class (MonoHandle handle)
+{
+ return handle->obj->vtable->klass;
+}
+
+static inline MonoDomain*
+mono_handle_domain (MonoHandle handle)
+{
+ return handle->obj->vtable->domain;
+}
+
+#define MONO_HANDLE_TYPE_DECL(type) typedef struct { type *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)->obj))
+
+#define MONO_HANDLE_ASSIGN(handle,rawptr) \
+ do { \
+ mono_handle_assign ((handle), (rawptr)); \
+ } while (0)
+
+#define MONO_HANDLE_SETREF(handle,fieldname,value) \
+ do { \
+ MonoHandle __value = (MonoHandle) (value); \
+ MONO_PREPARE_CRITICAL; \
+ MONO_OBJECT_SETREF (mono_handle_obj ((handle)), fieldname, mono_handle_obj (__value)); \
+ MONO_FINISH_CRITICAL; \
+ } while (0)
+
+#define MONO_HANDLE_SET(handle,fieldname,value) \
+ do { \
+ MONO_PREPARE_CRITICAL; \
+ mono_handle_obj ((handle))->fieldname = (value); \
+ MONO_FINISH_CRITICAL; \
+ } while (0)
+
+#define MONO_HANDLE_ARRAY_SETREF(handle,index,value) \
+ do { \
+ MonoHandle __value = (MonoHandle) (value); \
+ MONO_PREPARE_CRITICAL; \
+ mono_array_setref (mono_handle_obj ((handle)), (index), mono_handle_obj (__value)); \
+ MONO_FINISH_CRITICAL; \
+ } while (0)
+
+#define MONO_HANDLE_ARRAY_SET(handle,type,index,value) \
+ do { \
+ MONO_PREPARE_CRITICAL; \
+ mono_array_set (mono_handle_obj ((handle)), (type), (index), (value)); \
+ MONO_FINISH_CRITICAL; \
+ } while (0)
+
+/* handle arena specific functions */
+
+typedef struct _MonoHandleArena MonoHandleArena;
+
+gsize
+mono_handle_arena_size (gsize nb_handles);
+
+MonoHandle
+mono_handle_new (MonoObject *rawptr);
+
+MonoHandle
+mono_handle_elevate (MonoHandle handle);
+
+/* Some common handle types */
+
+MONO_HANDLE_TYPE_DECL (MonoArray);
+MONO_HANDLE_TYPE_DECL (MonoString);
+
+G_END_DECLS
+
+#endif /* __MONO_HANDLE_H__ */
MONO_ROOT_SOURCE_THREAD_POOL = 12,
// Roots in the debugger agent.
MONO_ROOT_SOURCE_DEBUGGER = 13,
+ // Handle structures, used for object passed to internal functions
+ MONO_ROOT_SOURCE_HANDLE = 14,
} MonoGCRootSource;
MONO_API void mono_gc_collect (int generation);
#include <mono/metadata/mempool.h>
#include <mono/metadata/class-internals.h>
#include <mono/metadata/threads-types.h>
+#include <mono/metadata/handle.h>
#include <mono/io-layer/io-layer.h>
#include "mono/utils/mono-compiler.h"
#include "mono/utils/mono-error.h"
MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
thread->thread_pinning_ref = NULL;
}
+
}
/*
/test-mono-linked-list-set
/test-sgen-qsort
/test-conc-hashtable
+/test-mono-handle
\ No newline at end of file
test_conc_hashtable_LDADD = $(test_ldadd)
test_conc_hashtable_LDFLAGS = $(test_ldflags)
-noinst_PROGRAMS = test-sgen-qsort test-memfuncs test-mono-linked-list-set test-conc-hashtable
+test_mono_handle_SOURCES = test-mono-handle.c
+test_mono_handle_CFLAGS = $(test_cflags)
+test_mono_handle_LDADD = $(test_ldadd)
+test_mono_handle_LDFLAGS = $(test_ldflags)
-TESTS = test-sgen-qsort test-memfuncs test-mono-linked-list-set test-conc-hashtable
+noinst_PROGRAMS = test-sgen-qsort test-memfuncs test-mono-linked-list-set test-conc-hashtable test-mono-handle
+
+TESTS = test-sgen-qsort test-memfuncs test-mono-linked-list-set test-conc-hashtable test-mono-handle
.NOTPARALLEL:
--- /dev/null
+/*
+ * test-mono-handle: tests for MonoHandle and MonoHandleArena
+ *
+ * Authors:
+ * Aleksey Kliger <aleksey@xamarin.com>
+ *
+ * Copyright 2015 Xamarin, Inc. (www.xamarin.com)
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <mono/metadata/handle.h>
+#include <mono/metadata/handle-private.h>
+
+static void
+test1_arena_size ()
+{
+ for (gsize i = 1; i < 10; ++i) {
+ gsize sz = mono_handle_arena_size(i);
+ g_assert(sz >= i*sizeof(MonoHandle));
+ }
+}
+
+static void
+test2_arena_push_pop ()
+{
+ MonoHandleArena *top = NULL;
+
+ const int n_handles = 3;
+ MonoHandleArena *new_arena1 = g_malloc0 (mono_handle_arena_size (n_handles));
+ mono_handle_arena_stack_push (&top, new_arena1, n_handles);
+
+ MonoHandleArena *new_arena2 = g_malloc0 (mono_handle_arena_size (n_handles));
+
+ mono_handle_arena_stack_push (&top, new_arena2, n_handles);
+
+ g_assert (top == new_arena2);
+
+ mono_handle_arena_stack_pop (&top, new_arena2, n_handles);
+
+ g_free (new_arena2);
+
+ g_assert (top == new_arena1);
+
+ mono_handle_arena_stack_pop (&top, new_arena1, n_handles);
+
+ g_assert (top == NULL);
+
+ g_free (new_arena1);
+}
+
+
+
+int
+main (int argc, const char* argv[])
+{
+ test1_arena_size ();
+
+ test2_arena_push_pop ();
+
+ return 0;
+}