1 /* Borrowed from ./boehm-gc.c */
8 #include <mono/metadata/mono-gc.h>
9 #include <mono/metadata/gc-internals.h>
10 #include <mono/metadata/profiler-private.h>
11 #include <mono/utils/mono-compiler.h>
12 #include <mono/metadata/null-gc-handles.h>
17 #define HIDE_POINTER(obj) (obj)
18 #define REVEAL_POINTER(obj) (obj)
20 #define GC_call_with_alloc_lock(fnptr,arg) ((fnptr)((arg)))
22 static mono_mutex_t handle_section
;
23 #define lock_handles(handles) mono_os_mutex_lock (&handle_section)
24 #define unlock_handles(handles) mono_os_mutex_unlock (&handle_section)
31 guint slot_hint
: 24; /* starting slot for search in bitmap */
32 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
33 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
37 #define EMPTY_HANDLE_DATA(type) {NULL, NULL, 0, (type), 0, NULL}
39 /* weak and weak-track arrays will be allocated in malloc memory
41 static HandleData gc_handles
[] = {
42 EMPTY_HANDLE_DATA (HANDLE_WEAK
),
43 EMPTY_HANDLE_DATA (HANDLE_WEAK_TRACK
),
44 EMPTY_HANDLE_DATA (HANDLE_NORMAL
),
45 EMPTY_HANDLE_DATA (HANDLE_PINNED
)
48 #define BITMAP_SIZE (sizeof (*((HandleData *)NULL)->bitmap) * CHAR_BIT)
51 null_gc_handles_init (void)
53 mono_os_mutex_init_recursive (&handle_section
);
57 mono_gc_weak_link_add (void **link_addr
, MonoObject
*obj
, gboolean track
)
59 /* libgc requires that we use HIDE_POINTER... */
60 *link_addr
= (void*)HIDE_POINTER (obj
);
64 mono_gc_weak_link_remove (void **link_addr
, gboolean track
)
70 reveal_link (gpointer link_addr
)
72 void **link_a
= (void **)link_addr
;
73 return REVEAL_POINTER (*link_a
);
77 mono_gc_weak_link_get (void **link_addr
)
79 MonoObject
*obj
= (MonoObject
*)GC_call_with_alloc_lock (reveal_link
, link_addr
);
80 if (obj
== (MonoObject
*) -1)
86 slot_occupied (HandleData
*handles
, guint slot
) {
87 return handles
->bitmap
[slot
/ BITMAP_SIZE
] & (1 << (slot
% BITMAP_SIZE
));
91 vacate_slot (HandleData
*handles
, guint slot
) {
92 handles
->bitmap
[slot
/ BITMAP_SIZE
] &= ~(1 << (slot
% BITMAP_SIZE
));
96 occupy_slot (HandleData
*handles
, guint slot
) {
97 handles
->bitmap
[slot
/ BITMAP_SIZE
] |= 1 << (slot
% BITMAP_SIZE
);
101 find_first_unset (guint32 bitmap
)
104 for (i
= 0; i
< 32; ++i
) {
105 if (!(bitmap
& (1 << i
)))
112 handle_data_alloc_entries (HandleData
*handles
)
115 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles
->type
)) {
116 handles
->entries
= (void **)g_malloc0 (sizeof (*handles
->entries
) * handles
->size
);
117 handles
->domain_ids
= (guint16
*)g_malloc0 (sizeof (*handles
->domain_ids
) * handles
->size
);
119 handles
->entries
= (void **)mono_gc_alloc_fixed (sizeof (*handles
->entries
) * handles
->size
, NULL
, MONO_ROOT_SOURCE_GC_HANDLE
, "GC Handle Table (Null)");
121 handles
->bitmap
= (guint32
*)g_malloc0 (handles
->size
/ CHAR_BIT
);
125 handle_data_next_unset (HandleData
*handles
)
128 for (slot
= handles
->slot_hint
; slot
< handles
->size
/ BITMAP_SIZE
; ++slot
) {
129 if (handles
->bitmap
[slot
] == 0xffffffff)
131 handles
->slot_hint
= slot
;
132 return find_first_unset (handles
->bitmap
[slot
]);
138 handle_data_first_unset (HandleData
*handles
)
141 for (slot
= 0; slot
< handles
->slot_hint
; ++slot
) {
142 if (handles
->bitmap
[slot
] == 0xffffffff)
144 handles
->slot_hint
= slot
;
145 return find_first_unset (handles
->bitmap
[slot
]);
150 /* Returns the index of the current slot in the bitmap. */
152 handle_data_grow (HandleData
*handles
, gboolean track
)
155 guint32 new_size
= handles
->size
* 2; /* always double: we memset to 0 based on this below */
157 /* resize and copy the bitmap */
158 new_bitmap
= (guint32
*)g_malloc0 (new_size
/ CHAR_BIT
);
159 memcpy (new_bitmap
, handles
->bitmap
, handles
->size
/ CHAR_BIT
);
160 g_free (handles
->bitmap
);
161 handles
->bitmap
= new_bitmap
;
163 /* resize and copy the entries */
164 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles
->type
)) {
168 domain_ids
= (guint16
*)g_malloc0 (sizeof (*handles
->domain_ids
) * new_size
);
169 entries
= (void **)g_malloc0 (sizeof (*handles
->entries
) * new_size
);
170 memcpy (domain_ids
, handles
->domain_ids
, sizeof (*handles
->domain_ids
) * handles
->size
);
171 for (i
= 0; i
< handles
->size
; ++i
) {
172 MonoObject
*obj
= mono_gc_weak_link_get (&(handles
->entries
[i
]));
174 mono_gc_weak_link_add (&(entries
[i
]), obj
, track
);
175 mono_gc_weak_link_remove (&(handles
->entries
[i
]), track
);
177 g_assert (!handles
->entries
[i
]);
180 g_free (handles
->entries
);
181 g_free (handles
->domain_ids
);
182 handles
->entries
= entries
;
183 handles
->domain_ids
= domain_ids
;
186 entries
= (void **)mono_gc_alloc_fixed (sizeof (*handles
->entries
) * new_size
, NULL
, MONO_ROOT_SOURCE_GC_HANDLE
, "GC Handle Table (Null)");
187 mono_gc_memmove_aligned (entries
, handles
->entries
, sizeof (*handles
->entries
) * handles
->size
);
188 mono_gc_free_fixed (handles
->entries
);
189 handles
->entries
= entries
;
191 handles
->slot_hint
= handles
->size
/ BITMAP_SIZE
;
192 handles
->size
= new_size
;
196 alloc_handle (HandleData
*handles
, MonoObject
*obj
, gboolean track
)
200 lock_handles (handles
);
202 handle_data_alloc_entries (handles
);
203 i
= handle_data_next_unset (handles
);
204 if (i
== -1 && handles
->slot_hint
!= 0)
205 i
= handle_data_first_unset (handles
);
207 handle_data_grow (handles
, track
);
210 slot
= handles
->slot_hint
* BITMAP_SIZE
+ i
;
211 occupy_slot (handles
, slot
);
212 handles
->entries
[slot
] = NULL
;
213 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles
->type
)) {
214 /*FIXME, what to use when obj == null?*/
215 handles
->domain_ids
[slot
] = (obj
? mono_object_get_domain_internal (obj
) : mono_domain_get ())->domain_id
;
217 mono_gc_weak_link_add (&(handles
->entries
[slot
]), obj
, track
);
219 handles
->entries
[slot
] = obj
;
222 #ifndef DISABLE_PERFCOUNTERS
223 mono_atomic_inc_i32 (&mono_perfcounters
->gc_num_handles
);
225 unlock_handles (handles
);
226 res
= MONO_GC_HANDLE (slot
, handles
->type
);
227 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED
, handles
->type
, res
, obj
);
233 * \param obj managed object to get a handle for
234 * \param pinned whether the object should be pinned
236 * This returns a handle that wraps the object, this is used to keep a
237 * reference to a managed object from the unmanaged world and preventing the
238 * object from being disposed.
240 * If \p pinned is false the address of the object can not be obtained, if it is
241 * true the address of the object can be obtained. This will also pin the
242 * object so it will not be possible by a moving garbage collector to move the
245 * \returns a handle that can be used to access the object from
249 mono_gchandle_new_internal (MonoObject
*obj
, gboolean pinned
)
251 return alloc_handle (&gc_handles
[pinned
? HANDLE_PINNED
: HANDLE_NORMAL
], obj
, FALSE
);
255 * mono_gchandle_new_weakref_internal:
256 * \param obj managed object to get a handle for
257 * \param track_resurrection Determines how long to track the object, if this is set to TRUE, the object is tracked after finalization, if FALSE, the object is only tracked up until the point of finalization.
259 * This returns a weak handle that wraps the object, this is used to
260 * keep a reference to a managed object from the unmanaged world.
261 * Unlike the \c mono_gchandle_new_internal the object can be reclaimed by the
262 * garbage collector. In this case the value of the GCHandle will be
265 * If \p track_resurrection is TRUE the object will be tracked through
266 * finalization and if the object is resurrected during the execution
267 * of the finalizer, then the returned weakref will continue to hold
268 * a reference to the object. If \p track_resurrection is FALSE, then
269 * the weak reference's target will become NULL as soon as the object
270 * is passed on to the finalizer.
272 * \returns a handle that can be used to access the object from
276 mono_gchandle_new_weakref_internal (MonoObject
*obj
, gboolean track_resurrection
)
278 return alloc_handle (&gc_handles
[track_resurrection
? HANDLE_WEAK_TRACK
: HANDLE_WEAK
], obj
, track_resurrection
);
282 * mono_gchandle_get_target:
283 * \param gchandle a GCHandle's handle.
285 * The handle was previously created by calling \c mono_gchandle_new_internal or
286 * \c mono_gchandle_new_weakref.
288 * \returns A pointer to the \c MonoObject* represented by the handle or
289 * NULL for a collected object if using a weakref handle.
292 mono_gchandle_get_target_internal (guint32 gchandle
)
294 guint slot
= MONO_GC_HANDLE_SLOT (gchandle
);
295 guint type
= MONO_GC_HANDLE_TYPE (gchandle
);
296 HandleData
*handles
= &gc_handles
[type
];
297 MonoObject
*obj
= NULL
;
298 if (type
>= HANDLE_TYPE_MAX
)
301 lock_handles (handles
);
302 if (slot
< handles
->size
&& slot_occupied (handles
, slot
)) {
303 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles
->type
)) {
304 obj
= mono_gc_weak_link_get (&handles
->entries
[slot
]);
306 obj
= (MonoObject
*)handles
->entries
[slot
];
309 /* print a warning? */
311 unlock_handles (handles
);
312 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
317 mono_gchandle_set_target (guint32 gchandle
, MonoObject
*obj
)
319 guint slot
= MONO_GC_HANDLE_SLOT (gchandle
);
320 guint type
= MONO_GC_HANDLE_TYPE (gchandle
);
321 HandleData
*handles
= &gc_handles
[type
];
322 MonoObject
*old_obj
= NULL
;
324 g_assert (type
< HANDLE_TYPE_MAX
);
325 lock_handles (handles
);
326 if (slot
< handles
->size
&& slot_occupied (handles
, slot
)) {
327 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles
->type
)) {
328 old_obj
= (MonoObject
*)handles
->entries
[slot
];
329 if (handles
->entries
[slot
])
330 mono_gc_weak_link_remove (&handles
->entries
[slot
], handles
->type
== HANDLE_WEAK_TRACK
);
332 mono_gc_weak_link_add (&handles
->entries
[slot
], obj
, handles
->type
== HANDLE_WEAK_TRACK
);
333 /*FIXME, what to use when obj == null?*/
334 handles
->domain_ids
[slot
] = (obj
? mono_object_get_domain_internal (obj
) : mono_domain_get ())->domain_id
;
336 handles
->entries
[slot
] = obj
;
339 /* print a warning? */
341 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
342 unlock_handles (handles
);
346 * mono_gchandle_is_in_domain:
347 * \param gchandle a GCHandle's handle.
348 * \param domain An application domain.
350 * Use this function to determine if the \p gchandle points to an
351 * object allocated in the specified \p domain.
353 * \returns TRUE if the object wrapped by the \p gchandle belongs to the specific \p domain.
356 mono_gchandle_is_in_domain (guint32 gchandle
, MonoDomain
*domain
)
358 guint slot
= MONO_GC_HANDLE_SLOT (gchandle
);
359 guint type
= MONO_GC_HANDLE_TYPE (gchandle
);
360 HandleData
*handles
= &gc_handles
[type
];
361 gboolean result
= FALSE
;
363 if (type
>= HANDLE_TYPE_MAX
)
366 lock_handles (handles
);
367 if (slot
< handles
->size
&& slot_occupied (handles
, slot
)) {
368 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles
->type
)) {
369 result
= domain
->domain_id
== handles
->domain_ids
[slot
];
372 obj
= (MonoObject
*)handles
->entries
[slot
];
376 result
= domain
== mono_object_domain (obj
);
379 /* print a warning? */
381 unlock_handles (handles
);
386 * mono_gchandle_free:
387 * \param gchandle a GCHandle's handle.
389 * Frees the \p gchandle handle. If there are no outstanding
390 * references, the garbage collector can reclaim the memory of the
394 mono_gchandle_free_internal (guint32 gchandle
)
399 guint slot
= MONO_GC_HANDLE_SLOT (gchandle
);
400 guint type
= MONO_GC_HANDLE_TYPE (gchandle
);
401 HandleData
*handles
= &gc_handles
[type
];
402 if (type
>= HANDLE_TYPE_MAX
)
405 lock_handles (handles
);
406 if (slot
< handles
->size
&& slot_occupied (handles
, slot
)) {
407 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles
->type
)) {
408 if (handles
->entries
[slot
])
409 mono_gc_weak_link_remove (&handles
->entries
[slot
], handles
->type
== HANDLE_WEAK_TRACK
);
411 handles
->entries
[slot
] = NULL
;
413 vacate_slot (handles
, slot
);
415 /* print a warning? */
417 #ifndef DISABLE_PERFCOUNTERS
418 mono_atomic_dec_i32 (&mono_perfcounters
->gc_num_handles
);
420 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
421 unlock_handles (handles
);
422 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED
, handles
->type
, gchandle
, NULL
);
426 * mono_gchandle_free_domain:
427 * \param domain domain that is unloading
429 * Function used internally to cleanup any GC handle for objects belonging
430 * to the specified domain during appdomain unload.
433 mono_gchandle_free_domain (MonoDomain
*domain
)
437 for (type
= HANDLE_TYPE_MIN
; type
< HANDLE_PINNED
; ++type
) {
439 HandleData
*handles
= &gc_handles
[type
];
440 lock_handles (handles
);
441 for (slot
= 0; slot
< handles
->size
; ++slot
) {
442 if (!slot_occupied (handles
, slot
))
444 if (MONO_GC_HANDLE_TYPE_IS_WEAK (type
)) {
445 if (domain
->domain_id
== handles
->domain_ids
[slot
]) {
446 vacate_slot (handles
, slot
);
447 if (handles
->entries
[slot
])
448 mono_gc_weak_link_remove (&handles
->entries
[slot
], handles
->type
== HANDLE_WEAK_TRACK
);
451 if (handles
->entries
[slot
] && mono_object_domain (handles
->entries
[slot
]) == domain
) {
452 vacate_slot (handles
, slot
);
453 handles
->entries
[slot
] = NULL
;
457 unlock_handles (handles
);
463 MONO_EMPTY_SOURCE_FILE (null_gc_handles
);
464 #endif /* HAVE_NULL_GC */