[coop] Introduce new runtime handle API
[mono-project.git] / mono / metadata / handle.c
blob10c573a1a7096ed3e3e02e2cc3ada15537e77b32
1 /*
2 * handle.c: Handle to object in native code
4 * Authors:
5 * - Ludovic Henry <ludovic@xamarin.com>
7 * Copyright 2015 Xamarin, Inc. (www.xamarin.com)
8 */
10 #include <config.h>
11 #include <glib.h>
13 #include <mono/metadata/handle.h>
14 #include <mono/metadata/handle-private.h>
15 #include <mono/metadata/object-internals.h>
16 #include <mono/metadata/gc-internals.h>
17 #include <mono/utils/atomic.h>
18 #include <mono/utils/mono-lazy-init.h>
20 #define HANDLES_PER_CHUNK (16 - 3)
22 typedef struct _MonoHandleArenaChunk MonoHandleArenaChunk;
23 struct _MonoHandleArenaChunk {
24 MonoHandleArenaChunk *next;
25 gsize handles_capacity;
26 gsize handles_size;
27 MonoHandleStorage handles [MONO_ZERO_LEN_ARRAY];
30 struct _MonoHandleArena {
31 MonoHandleArenaChunk *chunk;
32 MonoHandleArenaChunk *chunk_last;
33 MonoHandleArena *prev;
36 static mono_lazy_init_t arena_status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
38 #ifdef HAVE_SGEN_GC
39 static MonoGCDescriptor arena_desc = MONO_GC_DESCRIPTOR_NULL;
40 #endif
42 static MonoHandleArenaChunk *chunk_free_list = NULL;
44 static inline MonoHandleArenaChunk*
45 chunk_alloc (void)
47 MonoHandleArenaChunk *old, *new;
49 do {
50 old = chunk_free_list;
51 if (!old) {
52 MonoHandleArenaChunk *chunk;
54 chunk = g_malloc0 (sizeof (MonoHandleArenaChunk) + sizeof (MonoHandleStorage) * (HANDLES_PER_CHUNK - MONO_ZERO_LEN_ARRAY));
55 chunk->handles_capacity = HANDLES_PER_CHUNK;
57 return chunk;
60 new = old->next;
61 } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, new, old) != old);
63 memset (old, 0, sizeof (MonoHandleArenaChunk));
64 return old;
67 static inline void
68 chunk_free (MonoHandleArenaChunk *chunk)
70 do {
71 chunk->next = chunk_free_list;
72 } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
75 static MonoHandle
76 handle_new (MonoHandleArena *arena, MonoObject *obj)
78 MonoHandleArenaChunk *chunk;
80 g_assert (arena->chunk);
81 g_assert (arena->chunk_last);
83 chunk = arena->chunk_last;
85 if (chunk->handles_size < chunk->handles_capacity) {
86 chunk->handles [chunk->handles_size].obj = obj;
87 chunk->handles_size += 1;
89 return &chunk->handles [chunk->handles_size - 1];
92 chunk = chunk->next = chunk_alloc ();
94 chunk->handles [0].obj = obj;
95 chunk->handles_size = 1;
97 arena->chunk_last = chunk;
99 return &chunk->handles [0];
102 MonoHandle
103 mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj)
105 g_assert (arena);
106 return handle_new (arena, obj);
109 MonoHandle
110 mono_handle_new (MonoObject *obj)
112 /* TODO: finish implementation by placing an arena somewhere
113 * in the current thread */
114 g_assert_not_reached ();
115 MonoHandleArena *arena = NULL;
116 return mono_handle_arena_new (arena, obj);
120 * Elevate the handle to the parent arena
122 MonoHandle
123 mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle)
125 g_assert (handle);
126 g_assert (arena);
127 g_assert (arena->prev);
129 return handle_new (arena->prev, handle->obj);
132 MonoHandle
133 mono_handle_elevate (MonoHandle handle)
135 /* TODO: finish implementation by placing an arena somewhere
136 * in the current thread */
137 g_assert_not_reached ();
138 MonoHandleArena *arena = NULL;
139 return mono_handle_arena_elevate (arena, handle);
142 gsize
143 mono_handle_arena_size (gsize nb_handles)
145 g_assert (nb_handles > 0);
146 return sizeof (MonoHandleArena) + sizeof (MonoHandleArenaChunk) + sizeof (MonoHandle) * (MAX (nb_handles, HANDLES_PER_CHUNK) - MONO_ZERO_LEN_ARRAY);
149 void
150 mono_handle_arena_stack_push(MonoHandleArena **arena_stack, MonoHandleArena *arena, gsize nb_handles)
152 g_assert (arena_stack);
153 g_assert (arena);
155 arena->prev = *arena_stack;
156 arena->chunk = arena->chunk_last = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
158 arena->chunk->next = NULL;
159 arena->chunk->handles_capacity = MAX (nb_handles, HANDLES_PER_CHUNK);
160 arena->chunk->handles_size = 0;
161 memset (&arena->chunk->handles [0], 0, sizeof (MonoHandle) * arena->chunk->handles_capacity);
163 *arena_stack = arena;
166 void
167 mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *arena, gsize nb_handles)
169 MonoHandleArenaChunk *chunk, *next;
171 g_assert (arena);
172 g_assert (arena->chunk);
173 g_assert (arena->chunk_last);
174 g_assert (arena_stack);
176 *arena_stack = arena->prev;
178 for (chunk = arena->chunk; chunk; chunk = next) {
179 next = chunk->next;
180 memset (&chunk->handles [0], 0, sizeof (MonoHandle) * chunk->handles_capacity);
181 if (chunk != arena->chunk)
182 chunk_free (chunk);
186 static void
187 arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
189 MonoHandleArena *arena;
190 MonoHandleArenaChunk *chunk;
191 int i;
193 for (arena = *(MonoHandleArena**) addr; arena; arena = arena->prev) {
194 for (chunk = arena->chunk; chunk; chunk = chunk->next) {
195 for (i = 0; i < chunk->handles_size; ++i) {
196 if (chunk->handles [i].obj != NULL)
197 mark_func (&chunk->handles [i].obj, gc_data);
203 static void
204 initialize (void)
206 #ifdef HAVE_SGEN_GC
207 arena_desc = mono_gc_make_root_descr_user (arena_scan);
208 #endif
211 void
212 mono_handle_arena_initialize (MonoHandleArena **arena_stack)
214 #ifdef HAVE_SGEN_GC
215 mono_lazy_initialize (&arena_status, initialize);
216 mono_gc_register_root ((char*) arena_stack, sizeof (MonoHandleArena*), arena_desc, MONO_ROOT_SOURCE_HANDLE, "runtime threads handle arena");
217 #endif
220 void
221 mono_handle_arena_deinitialize (MonoHandleArena **arena_stack)
223 #ifdef HAVE_SGEN_GC
224 mono_gc_deregister_root ((char*) arena_stack);
225 #endif