2 * handle.c: Handle to object in native code
5 * - Ludovic Henry <ludovic@xamarin.com>
7 * Copyright 2015 Xamarin, Inc. (www.xamarin.com)
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;
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;
39 static MonoGCDescriptor arena_desc = MONO_GC_DESCRIPTOR_NULL;
42 static MonoHandleArenaChunk *chunk_free_list = NULL;
44 static inline MonoHandleArenaChunk*
47 MonoHandleArenaChunk *old, *new;
50 old = chunk_free_list;
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;
61 } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, new, old) != old);
63 memset (old, 0, sizeof (MonoHandleArenaChunk));
68 chunk_free (MonoHandleArenaChunk *chunk)
71 chunk->next = chunk_free_list;
72 } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
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];
103 mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj)
106 return handle_new (arena, obj);
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
123 mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle)
127 g_assert (arena->prev);
129 return handle_new (arena->prev, handle->obj);
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);
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);
150 mono_handle_arena_stack_push(MonoHandleArena **arena_stack, MonoHandleArena *arena, gsize nb_handles)
152 g_assert (arena_stack);
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;
167 mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *arena, gsize nb_handles)
169 MonoHandleArenaChunk *chunk, *next;
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) {
180 memset (&chunk->handles [0], 0, sizeof (MonoHandle) * chunk->handles_capacity);
181 if (chunk != arena->chunk)
187 arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
189 MonoHandleArena *arena;
190 MonoHandleArenaChunk *chunk;
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);
207 arena_desc = mono_gc_make_root_descr_user (arena_scan);
212 mono_handle_arena_initialize (MonoHandleArena **arena_stack)
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");
221 mono_handle_arena_deinitialize (MonoHandleArena **arena_stack)
224 mono_gc_deregister_root ((char*) arena_stack);