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
);