5b036f433839d194f0934941d1149789b272ffe3
[mono.git] / mono / metadata / gc.c
1 /*
2  * metadata/gc.c: GC icalls.
3  *
4  * Author: Paolo Molaro <lupus@ximian.com>
5  *
6  * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
7  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
8  * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
9  */
10
11 #include <config.h>
12 #include <glib.h>
13 #include <string.h>
14 #include <errno.h>
15
16 #include <mono/metadata/gc-internal.h>
17 #include <mono/metadata/mono-gc.h>
18 #include <mono/metadata/threads.h>
19 #include <mono/metadata/tabledefs.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/domain-internals.h>
23 #include <mono/metadata/class-internals.h>
24 #include <mono/metadata/metadata-internals.h>
25 #include <mono/metadata/mono-mlist.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/threadpool-internals.h>
28 #include <mono/metadata/threads-types.h>
29 #include <mono/utils/mono-logger-internal.h>
30 #include <mono/metadata/gc-internal.h>
31 #include <mono/metadata/marshal.h> /* for mono_delegate_free_ftnptr () */
32 #include <mono/metadata/attach.h>
33 #include <mono/metadata/console-io.h>
34 #include <mono/utils/mono-semaphore.h>
35 #include <mono/utils/mono-memory-model.h>
36 #include <mono/utils/mono-counters.h>
37 #include <mono/utils/dtrace.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/atomic.h>
40
41 #ifndef HOST_WIN32
42 #include <pthread.h>
43 #endif
44
45 typedef struct DomainFinalizationReq {
46         MonoDomain *domain;
47         HANDLE done_event;
48 } DomainFinalizationReq;
49
50 #ifdef PLATFORM_WINCE /* FIXME: add accessors to gc.dll API */
51 extern void (*__imp_GC_finalizer_notifier)(void);
52 #define GC_finalizer_notifier __imp_GC_finalizer_notifier
53 extern int __imp_GC_finalize_on_demand;
54 #define GC_finalize_on_demand __imp_GC_finalize_on_demand
55 #endif
56
57 static gboolean gc_disabled = FALSE;
58
59 static gboolean finalizing_root_domain = FALSE;
60
61 #define mono_finalizer_lock() EnterCriticalSection (&finalizer_mutex)
62 #define mono_finalizer_unlock() LeaveCriticalSection (&finalizer_mutex)
63 static CRITICAL_SECTION finalizer_mutex;
64 static CRITICAL_SECTION reference_queue_mutex;
65
66 static GSList *domains_to_finalize= NULL;
67 static MonoMList *threads_to_finalize = NULL;
68
69 static MonoInternalThread *gc_thread;
70
71 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
72
73 static void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj);
74
75 static void reference_queue_proccess_all (void);
76 static void mono_reference_queue_cleanup (void);
77 static void reference_queue_clear_for_domain (MonoDomain *domain);
78 #ifndef HAVE_NULL_GC
79 static HANDLE pending_done_event;
80 static HANDLE shutdown_event;
81 #endif
82
83 GCStats gc_stats;
84
85 static void
86 add_thread_to_finalize (MonoInternalThread *thread)
87 {
88         mono_finalizer_lock ();
89         if (!threads_to_finalize)
90                 MONO_GC_REGISTER_ROOT_SINGLE (threads_to_finalize);
91         threads_to_finalize = mono_mlist_append (threads_to_finalize, (MonoObject*)thread);
92         mono_finalizer_unlock ();
93 }
94
95 static gboolean suspend_finalizers = FALSE;
96 /* 
97  * actually, we might want to queue the finalize requests in a separate thread,
98  * but we need to be careful about the execution domain of the thread...
99  */
100 void
101 mono_gc_run_finalize (void *obj, void *data)
102 {
103         MonoObject *exc = NULL;
104         MonoObject *o;
105 #ifndef HAVE_SGEN_GC
106         MonoObject *o2;
107 #endif
108         MonoMethod* finalizer = NULL;
109         MonoDomain *caller_domain = mono_domain_get ();
110         MonoDomain *domain;
111         RuntimeInvokeFunction runtime_invoke;
112
113         o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
114
115         if (suspend_finalizers)
116                 return;
117
118         domain = o->vtable->domain;
119
120 #ifndef HAVE_SGEN_GC
121         mono_domain_finalizers_lock (domain);
122
123         o2 = g_hash_table_lookup (domain->finalizable_objects_hash, o);
124
125         mono_domain_finalizers_unlock (domain);
126
127         if (!o2)
128                 /* Already finalized somehow */
129                 return;
130 #endif
131
132         /* make sure the finalizer is not called again if the object is resurrected */
133         object_register_finalizer (obj, NULL);
134
135         if (o->vtable->klass == mono_defaults.internal_thread_class) {
136                 MonoInternalThread *t = (MonoInternalThread*)o;
137
138                 if (mono_gc_is_finalizer_internal_thread (t))
139                         /* Avoid finalizing ourselves */
140                         return;
141
142                 if (t->threadpool_thread && finalizing_root_domain) {
143                         /* Don't finalize threadpool threads when
144                            shutting down - they're finalized when the
145                            threadpool shuts down. */
146                         add_thread_to_finalize (t);
147                         return;
148                 }
149         }
150
151         if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
152                 /*
153                  * These can't be finalized during unloading/shutdown, since that would
154                  * free the native code which can still be referenced by other
155                  * finalizers.
156                  * FIXME: This is not perfect, objects dying at the same time as 
157                  * dynamic methods can still reference them even when !shutdown.
158                  */
159                 return;
160         }
161
162         if (mono_runtime_get_no_exec ())
163                 return;
164
165         /* speedup later... and use a timeout */
166         /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
167
168         /* Use _internal here, since this thread can enter a doomed appdomain */
169         mono_domain_set_internal (mono_object_domain (o));
170
171         /* delegates that have a native function pointer allocated are
172          * registered for finalization, but they don't have a Finalize
173          * method, because in most cases it's not needed and it's just a waste.
174          */
175         if (o->vtable->klass->delegate) {
176                 MonoDelegate* del = (MonoDelegate*)o;
177                 if (del->delegate_trampoline)
178                         mono_delegate_free_ftnptr ((MonoDelegate*)o);
179                 mono_domain_set_internal (caller_domain);
180                 return;
181         }
182
183         finalizer = mono_class_get_finalizer (o->vtable->klass);
184
185 #ifndef DISABLE_COM
186         /* If object has a CCW but has no finalizer, it was only
187          * registered for finalization in order to free the CCW.
188          * Else it needs the regular finalizer run.
189          * FIXME: what to do about ressurection and suppression
190          * of finalizer on object with CCW.
191          */
192         if (mono_marshal_free_ccw (o) && !finalizer) {
193                 mono_domain_set_internal (caller_domain);
194                 return;
195         }
196 #endif
197
198         /* 
199          * To avoid the locking plus the other overhead of mono_runtime_invoke (),
200          * create and precompile a wrapper which calls the finalize method using
201          * a CALLVIRT.
202          */
203         if (!domain->finalize_runtime_invoke) {
204                 MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
205
206                 domain->finalize_runtime_invoke = mono_compile_method (invoke);
207         }
208
209         runtime_invoke = domain->finalize_runtime_invoke;
210
211         mono_runtime_class_init (o->vtable);
212
213         if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) {
214                 MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size (o),
215                                 o->vtable->klass->name_space, o->vtable->klass->name);
216         }
217
218         runtime_invoke (o, NULL, &exc, NULL);
219
220         if (exc)
221                 mono_internal_thread_unhandled_exception (exc);
222
223         mono_domain_set_internal (caller_domain);
224 }
225
226 void
227 mono_gc_finalize_threadpool_threads (void)
228 {
229         while (threads_to_finalize) {
230                 MonoInternalThread *thread = (MonoInternalThread*) mono_mlist_get_data (threads_to_finalize);
231
232                 /* Force finalization of the thread. */
233                 thread->threadpool_thread = FALSE;
234                 mono_object_register_finalizer ((MonoObject*)thread);
235
236                 mono_gc_run_finalize (thread, NULL);
237
238                 threads_to_finalize = mono_mlist_next (threads_to_finalize);
239         }
240 }
241
242 gpointer
243 mono_gc_out_of_memory (size_t size)
244 {
245         /* 
246          * we could allocate at program startup some memory that we could release 
247          * back to the system at this point if we're really low on memory (ie, size is
248          * lower than the memory we set apart)
249          */
250         mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
251
252         return NULL;
253 }
254
255 /*
256  * Some of our objects may point to a different address than the address returned by GC_malloc()
257  * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
258  * This also means that in the callback we need to adjust the pointer to get back the real
259  * MonoObject*.
260  * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer, 
261  * since that, too, can cause the underlying pointer to be offset.
262  */
263 static void
264 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
265 {
266 #if HAVE_BOEHM_GC
267         guint offset = 0;
268         MonoDomain *domain;
269
270         if (obj == NULL)
271                 mono_raise_exception (mono_get_exception_argument_null ("obj"));
272         
273         domain = obj->vtable->domain;
274
275 #ifndef GC_DEBUG
276         /* This assertion is not valid when GC_DEBUG is defined */
277         g_assert (GC_base (obj) == (char*)obj - offset);
278 #endif
279
280         if (mono_domain_is_unloading (domain) && (callback != NULL))
281                 /*
282                  * Can't register finalizers in a dying appdomain, since they
283                  * could be invoked after the appdomain has been unloaded.
284                  */
285                 return;
286
287         mono_domain_finalizers_lock (domain);
288
289         if (callback)
290                 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
291         else
292                 g_hash_table_remove (domain->finalizable_objects_hash, obj);
293
294         mono_domain_finalizers_unlock (domain);
295
296         GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
297 #elif defined(HAVE_SGEN_GC)
298         if (obj == NULL)
299                 mono_raise_exception (mono_get_exception_argument_null ("obj"));
300
301         /*
302          * If we register finalizers for domains that are unloading we might
303          * end up running them while or after the domain is being cleared, so
304          * the objects will not be valid anymore.
305          */
306         if (!mono_domain_is_unloading (obj->vtable->domain))
307                 mono_gc_register_for_finalization (obj, callback);
308 #endif
309 }
310
311 /**
312  * mono_object_register_finalizer:
313  * @obj: object to register
314  *
315  * Records that object @obj has a finalizer, this will call the
316  * Finalize method when the garbage collector disposes the object.
317  * 
318  */
319 void
320 mono_object_register_finalizer (MonoObject *obj)
321 {
322         /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
323         object_register_finalizer (obj, mono_gc_run_finalize);
324 }
325
326 /**
327  * mono_domain_finalize:
328  * @domain: the domain to finalize
329  * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
330  *
331  *  Request finalization of all finalizable objects inside @domain. Wait
332  * @timeout msecs for the finalization to complete.
333  *
334  * Returns: TRUE if succeeded, FALSE if there was a timeout
335  */
336
337 gboolean
338 mono_domain_finalize (MonoDomain *domain, guint32 timeout) 
339 {
340         DomainFinalizationReq *req;
341         guint32 res;
342         HANDLE done_event;
343         MonoInternalThread *thread = mono_thread_internal_current ();
344
345         if (mono_thread_internal_current () == gc_thread)
346                 /* We are called from inside a finalizer, not much we can do here */
347                 return FALSE;
348
349         /* 
350          * No need to create another thread 'cause the finalizer thread
351          * is still working and will take care of running the finalizers
352          */ 
353         
354 #ifndef HAVE_NULL_GC
355         if (gc_disabled)
356                 return TRUE;
357
358         mono_gc_collect (mono_gc_max_generation ());
359
360         done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
361         if (done_event == NULL) {
362                 return FALSE;
363         }
364
365         req = g_new0 (DomainFinalizationReq, 1);
366         req->domain = domain;
367         req->done_event = done_event;
368
369         if (domain == mono_get_root_domain ())
370                 finalizing_root_domain = TRUE;
371         
372         mono_finalizer_lock ();
373
374         domains_to_finalize = g_slist_append (domains_to_finalize, req);
375
376         mono_finalizer_unlock ();
377
378         /* Tell the finalizer thread to finalize this appdomain */
379         mono_gc_finalize_notify ();
380
381         if (timeout == -1)
382                 timeout = INFINITE;
383
384         while (TRUE) {
385                 res = WaitForSingleObjectEx (done_event, timeout, TRUE);
386                 /* printf ("WAIT RES: %d.\n", res); */
387
388                 if (res == WAIT_IO_COMPLETION) {
389                         if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
390                                 return FALSE;
391                 } else if (res == WAIT_TIMEOUT) {
392                         /* We leak the handle here */
393                         return FALSE;
394                 } else {
395                         break;
396                 }
397         }
398
399         CloseHandle (done_event);
400
401         if (domain == mono_get_root_domain ()) {
402                 mono_thread_pool_cleanup ();
403                 mono_gc_finalize_threadpool_threads ();
404         }
405
406         return TRUE;
407 #else
408         /* We don't support domain finalization without a GC */
409         return FALSE;
410 #endif
411 }
412
413 void
414 ves_icall_System_GC_InternalCollect (int generation)
415 {
416         mono_gc_collect (generation);
417 }
418
419 gint64
420 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
421 {
422         MONO_ARCH_SAVE_REGS;
423
424         if (forceCollection)
425                 mono_gc_collect (mono_gc_max_generation ());
426         return mono_gc_get_used_size ();
427 }
428
429 void
430 ves_icall_System_GC_KeepAlive (MonoObject *obj)
431 {
432         MONO_ARCH_SAVE_REGS;
433
434         /*
435          * Does nothing.
436          */
437 }
438
439 void
440 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
441 {
442         if (!obj)
443                 mono_raise_exception (mono_get_exception_argument_null ("obj"));
444
445         object_register_finalizer (obj, mono_gc_run_finalize);
446 }
447
448 void
449 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
450 {
451         if (!obj)
452                 mono_raise_exception (mono_get_exception_argument_null ("obj"));
453
454         /* delegates have no finalizers, but we register them to deal with the
455          * unmanaged->managed trampoline. We don't let the user suppress it
456          * otherwise we'd leak it.
457          */
458         if (obj->vtable->klass->delegate)
459                 return;
460
461         /* FIXME: Need to handle case where obj has COM Callable Wrapper
462          * generated for it that needs cleaned up, but user wants to suppress
463          * their derived object finalizer. */
464
465         object_register_finalizer (obj, NULL);
466 }
467
468 void
469 ves_icall_System_GC_WaitForPendingFinalizers (void)
470 {
471 #ifndef HAVE_NULL_GC
472         if (!mono_gc_pending_finalizers ())
473                 return;
474
475         if (mono_thread_internal_current () == gc_thread)
476                 /* Avoid deadlocks */
477                 return;
478
479         /*
480         If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
481         be the one responsible for starting it up.
482         */
483         if (gc_thread == NULL)
484                 return;
485
486         ResetEvent (pending_done_event);
487         mono_gc_finalize_notify ();
488         /* g_print ("Waiting for pending finalizers....\n"); */
489         WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
490         /* g_print ("Done pending....\n"); */
491 #endif
492 }
493
494 void
495 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
496 {
497 #ifdef HAVE_SGEN_GC
498         if (!mono_gc_ephemeron_array_add (array))
499                 mono_raise_exception (mono_object_domain (array)->out_of_memory_ex);
500 #endif
501 }
502
503 MonoObject*
504 ves_icall_System_GC_get_ephemeron_tombstone (void)
505 {
506         return mono_domain_get ()->ephemeron_tombstone;
507 }
508
509 #define mono_allocator_lock() EnterCriticalSection (&allocator_section)
510 #define mono_allocator_unlock() LeaveCriticalSection (&allocator_section)
511 static CRITICAL_SECTION allocator_section;
512 static CRITICAL_SECTION handle_section;
513
514 typedef enum {
515         HANDLE_WEAK,
516         HANDLE_WEAK_TRACK,
517         HANDLE_NORMAL,
518         HANDLE_PINNED
519 } HandleType;
520
521 static HandleType mono_gchandle_get_type (guint32 gchandle);
522
523 MonoObject *
524 ves_icall_System_GCHandle_GetTarget (guint32 handle)
525 {
526         return mono_gchandle_get_target (handle);
527 }
528
529 /*
530  * if type == -1, change the target of the handle, otherwise allocate a new handle.
531  */
532 guint32
533 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
534 {
535         if (type == -1) {
536                 mono_gchandle_set_target (handle, obj);
537                 /* the handle doesn't change */
538                 return handle;
539         }
540         switch (type) {
541         case HANDLE_WEAK:
542                 return mono_gchandle_new_weakref (obj, FALSE);
543         case HANDLE_WEAK_TRACK:
544                 return mono_gchandle_new_weakref (obj, TRUE);
545         case HANDLE_NORMAL:
546                 return mono_gchandle_new (obj, FALSE);
547         case HANDLE_PINNED:
548                 return mono_gchandle_new (obj, TRUE);
549         default:
550                 g_assert_not_reached ();
551         }
552         return 0;
553 }
554
555 void
556 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
557 {
558         mono_gchandle_free (handle);
559 }
560
561 gpointer
562 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
563 {
564         MonoObject *obj;
565
566         if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
567                 return (gpointer)-2;
568         obj = mono_gchandle_get_target (handle);
569         if (obj) {
570                 MonoClass *klass = mono_object_class (obj);
571                 if (klass == mono_defaults.string_class) {
572                         return mono_string_chars ((MonoString*)obj);
573                 } else if (klass->rank) {
574                         return mono_array_addr ((MonoArray*)obj, char, 0);
575                 } else {
576                         /* the C# code will check and throw the exception */
577                         /* FIXME: missing !klass->blittable test, see bug #61134 */
578                         if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
579                                 return (gpointer)-1;
580                         return (char*)obj + sizeof (MonoObject);
581                 }
582         }
583         return NULL;
584 }
585
586 MonoBoolean
587 ves_icall_Mono_Runtime_SetGCAllowSynchronousMajor (MonoBoolean flag)
588 {
589         return mono_gc_set_allow_synchronous_major (flag);
590 }
591
592 typedef struct {
593         guint32  *bitmap;
594         gpointer *entries;
595         guint32   size;
596         guint8    type;
597         guint     slot_hint : 24; /* starting slot for search */
598         /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
599         /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
600         guint16  *domain_ids;
601 } HandleData;
602
603 /* weak and weak-track arrays will be allocated in malloc memory 
604  */
605 static HandleData gc_handles [] = {
606         {NULL, NULL, 0, HANDLE_WEAK, 0},
607         {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
608         {NULL, NULL, 0, HANDLE_NORMAL, 0},
609         {NULL, NULL, 0, HANDLE_PINNED, 0}
610 };
611
612 #define lock_handles(handles) EnterCriticalSection (&handle_section)
613 #define unlock_handles(handles) LeaveCriticalSection (&handle_section)
614
615 static int
616 find_first_unset (guint32 bitmap)
617 {
618         int i;
619         for (i = 0; i < 32; ++i) {
620                 if (!(bitmap & (1 << i)))
621                         return i;
622         }
623         return -1;
624 }
625
626 static void*
627 make_root_descr_all_refs (int numbits, gboolean pinned)
628 {
629 #ifdef HAVE_SGEN_GC
630         if (pinned)
631                 return NULL;
632 #endif
633         return mono_gc_make_root_descr_all_refs (numbits);
634 }
635
636 static guint32
637 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
638 {
639         gint slot, i;
640         guint32 res;
641         lock_handles (handles);
642         if (!handles->size) {
643                 handles->size = 32;
644                 if (handles->type > HANDLE_WEAK_TRACK) {
645                         handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED));
646                 } else {
647                         handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
648                         handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
649                 }
650                 handles->bitmap = g_malloc0 (handles->size / 8);
651         }
652         i = -1;
653         for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
654                 if (handles->bitmap [slot] != 0xffffffff) {
655                         i = find_first_unset (handles->bitmap [slot]);
656                         handles->slot_hint = slot;
657                         break;
658                 }
659         }
660         if (i == -1 && handles->slot_hint != 0) {
661                 for (slot = 0; slot < handles->slot_hint; ++slot) {
662                         if (handles->bitmap [slot] != 0xffffffff) {
663                                 i = find_first_unset (handles->bitmap [slot]);
664                                 handles->slot_hint = slot;
665                                 break;
666                         }
667                 }
668         }
669         if (i == -1) {
670                 guint32 *new_bitmap;
671                 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
672
673                 /* resize and copy the bitmap */
674                 new_bitmap = g_malloc0 (new_size / 8);
675                 memcpy (new_bitmap, handles->bitmap, handles->size / 8);
676                 g_free (handles->bitmap);
677                 handles->bitmap = new_bitmap;
678
679                 /* resize and copy the entries */
680                 if (handles->type > HANDLE_WEAK_TRACK) {
681                         gpointer *entries;
682
683                         entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED));
684                         mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
685
686                         mono_gc_free_fixed (handles->entries);
687                         handles->entries = entries;
688                 } else {
689                         gpointer *entries;
690                         guint16 *domain_ids;
691                         domain_ids = g_malloc0 (sizeof (guint16) * new_size);
692                         entries = g_malloc0 (sizeof (gpointer) * new_size);
693                         memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
694                         for (i = 0; i < handles->size; ++i) {
695                                 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
696                                 if (obj) {
697                                         mono_gc_weak_link_add (&(entries [i]), obj, track);
698                                         mono_gc_weak_link_remove (&(handles->entries [i]), track);
699                                 } else {
700                                         g_assert (!handles->entries [i]);
701                                 }
702                         }
703                         g_free (handles->entries);
704                         g_free (handles->domain_ids);
705                         handles->entries = entries;
706                         handles->domain_ids = domain_ids;
707                 }
708
709                 /* set i and slot to the next free position */
710                 i = 0;
711                 slot = (handles->size + 1) / 32;
712                 handles->slot_hint = handles->size + 1;
713                 handles->size = new_size;
714         }
715         handles->bitmap [slot] |= 1 << i;
716         slot = slot * 32 + i;
717         handles->entries [slot] = NULL;
718         if (handles->type <= HANDLE_WEAK_TRACK) {
719                 /*FIXME, what to use when obj == null?*/
720                 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
721                 if (obj)
722                         mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
723         } else {
724                 handles->entries [slot] = obj;
725         }
726
727 #ifndef DISABLE_PERFCOUNTERS
728         mono_perfcounters->gc_num_handles++;
729 #endif
730         unlock_handles (handles);
731         /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
732         res = (slot << 3) | (handles->type + 1);
733         mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
734         return res;
735 }
736
737 /**
738  * mono_gchandle_new:
739  * @obj: managed object to get a handle for
740  * @pinned: whether the object should be pinned
741  *
742  * This returns a handle that wraps the object, this is used to keep a
743  * reference to a managed object from the unmanaged world and preventing the
744  * object from being disposed.
745  * 
746  * If @pinned is false the address of the object can not be obtained, if it is
747  * true the address of the object can be obtained.  This will also pin the
748  * object so it will not be possible by a moving garbage collector to move the
749  * object. 
750  * 
751  * Returns: a handle that can be used to access the object from
752  * unmanaged code.
753  */
754 guint32
755 mono_gchandle_new (MonoObject *obj, gboolean pinned)
756 {
757         return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
758 }
759
760 /**
761  * mono_gchandle_new_weakref:
762  * @obj: managed object to get a handle for
763  * @pinned: whether the object should be pinned
764  *
765  * This returns a weak handle that wraps the object, this is used to
766  * keep a reference to a managed object from the unmanaged world.
767  * Unlike the mono_gchandle_new the object can be reclaimed by the
768  * garbage collector.  In this case the value of the GCHandle will be
769  * set to zero.
770  * 
771  * If @pinned is false the address of the object can not be obtained, if it is
772  * true the address of the object can be obtained.  This will also pin the
773  * object so it will not be possible by a moving garbage collector to move the
774  * object. 
775  * 
776  * Returns: a handle that can be used to access the object from
777  * unmanaged code.
778  */
779 guint32
780 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
781 {
782         guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
783
784         return handle;
785 }
786
787 static HandleType
788 mono_gchandle_get_type (guint32 gchandle)
789 {
790         guint type = (gchandle & 7) - 1;
791
792         return type;
793 }
794
795 /**
796  * mono_gchandle_get_target:
797  * @gchandle: a GCHandle's handle.
798  *
799  * The handle was previously created by calling mono_gchandle_new or
800  * mono_gchandle_new_weakref. 
801  *
802  * Returns a pointer to the MonoObject represented by the handle or
803  * NULL for a collected object if using a weakref handle.
804  */
805 MonoObject*
806 mono_gchandle_get_target (guint32 gchandle)
807 {
808         guint slot = gchandle >> 3;
809         guint type = (gchandle & 7) - 1;
810         HandleData *handles = &gc_handles [type];
811         MonoObject *obj = NULL;
812         if (type > 3)
813                 return NULL;
814         lock_handles (handles);
815         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
816                 if (handles->type <= HANDLE_WEAK_TRACK) {
817                         obj = mono_gc_weak_link_get (&handles->entries [slot]);
818                 } else {
819                         obj = handles->entries [slot];
820                 }
821         } else {
822                 /* print a warning? */
823         }
824         unlock_handles (handles);
825         /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
826         return obj;
827 }
828
829 static void
830 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
831 {
832         guint slot = gchandle >> 3;
833         guint type = (gchandle & 7) - 1;
834         HandleData *handles = &gc_handles [type];
835         MonoObject *old_obj = NULL;
836
837         if (type > 3)
838                 return;
839         lock_handles (handles);
840         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
841                 if (handles->type <= HANDLE_WEAK_TRACK) {
842                         old_obj = handles->entries [slot];
843                         if (handles->entries [slot])
844                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
845                         if (obj)
846                                 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
847                         /*FIXME, what to use when obj == null?*/
848                         handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
849                 } else {
850                         handles->entries [slot] = obj;
851                 }
852         } else {
853                 /* print a warning? */
854         }
855         /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
856         unlock_handles (handles);
857 }
858
859 /**
860  * mono_gchandle_is_in_domain:
861  * @gchandle: a GCHandle's handle.
862  * @domain: An application domain.
863  *
864  * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
865  */
866 gboolean
867 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
868 {
869         guint slot = gchandle >> 3;
870         guint type = (gchandle & 7) - 1;
871         HandleData *handles = &gc_handles [type];
872         gboolean result = FALSE;
873         if (type > 3)
874                 return FALSE;
875         lock_handles (handles);
876         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
877                 if (handles->type <= HANDLE_WEAK_TRACK) {
878                         result = domain->domain_id == handles->domain_ids [slot];
879                 } else {
880                         MonoObject *obj;
881                         obj = handles->entries [slot];
882                         if (obj == NULL)
883                                 result = TRUE;
884                         else
885                                 result = domain == mono_object_domain (obj);
886                 }
887         } else {
888                 /* print a warning? */
889         }
890         unlock_handles (handles);
891         return result;
892 }
893
894 /**
895  * mono_gchandle_free:
896  * @gchandle: a GCHandle's handle.
897  *
898  * Frees the @gchandle handle.  If there are no outstanding
899  * references, the garbage collector can reclaim the memory of the
900  * object wrapped. 
901  */
902 void
903 mono_gchandle_free (guint32 gchandle)
904 {
905         guint slot = gchandle >> 3;
906         guint type = (gchandle & 7) - 1;
907         HandleData *handles = &gc_handles [type];
908         if (type > 3)
909                 return;
910
911         lock_handles (handles);
912         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
913                 if (handles->type <= HANDLE_WEAK_TRACK) {
914                         if (handles->entries [slot])
915                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
916                 } else {
917                         handles->entries [slot] = NULL;
918                 }
919                 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
920         } else {
921                 /* print a warning? */
922         }
923 #ifndef DISABLE_PERFCOUNTERS
924         mono_perfcounters->gc_num_handles--;
925 #endif
926         /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
927         unlock_handles (handles);
928         mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
929 }
930
931 /**
932  * mono_gchandle_free_domain:
933  * @domain: domain that is unloading
934  *
935  * Function used internally to cleanup any GC handle for objects belonging
936  * to the specified domain during appdomain unload.
937  */
938 void
939 mono_gchandle_free_domain (MonoDomain *domain)
940 {
941         guint type;
942
943         for (type = 0; type < 3; ++type) {
944                 guint slot;
945                 HandleData *handles = &gc_handles [type];
946                 lock_handles (handles);
947                 for (slot = 0; slot < handles->size; ++slot) {
948                         if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
949                                 continue;
950                         if (type <= HANDLE_WEAK_TRACK) {
951                                 if (domain->domain_id == handles->domain_ids [slot]) {
952                                         handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
953                                         if (handles->entries [slot])
954                                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
955                                 }
956                         } else {
957                                 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
958                                         handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
959                                         handles->entries [slot] = NULL;
960                                 }
961                         }
962                 }
963                 unlock_handles (handles);
964         }
965
966 }
967
968 MonoBoolean
969 GCHandle_CheckCurrentDomain (guint32 gchandle)
970 {
971         return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
972 }
973
974 #ifndef HAVE_NULL_GC
975
976 #ifdef MONO_HAS_SEMAPHORES
977 static MonoSemType finalizer_sem;
978 #endif
979 static HANDLE finalizer_event;
980 static volatile gboolean finished=FALSE;
981
982 void
983 mono_gc_finalize_notify (void)
984 {
985 #ifdef DEBUG
986         g_message ( "%s: prodding finalizer", __func__);
987 #endif
988
989 #ifdef MONO_HAS_SEMAPHORES
990         MONO_SEM_POST (&finalizer_sem);
991 #else
992         SetEvent (finalizer_event);
993 #endif
994 }
995
996 #ifdef HAVE_BOEHM_GC
997
998 static void
999 collect_objects (gpointer key, gpointer value, gpointer user_data)
1000 {
1001         GPtrArray *arr = (GPtrArray*)user_data;
1002         g_ptr_array_add (arr, key);
1003 }
1004
1005 #endif
1006
1007 /*
1008  * finalize_domain_objects:
1009  *
1010  *  Run the finalizers of all finalizable objects in req->domain.
1011  */
1012 static void
1013 finalize_domain_objects (DomainFinalizationReq *req)
1014 {
1015         MonoDomain *domain = req->domain;
1016
1017 #if HAVE_SGEN_GC
1018 #define NUM_FOBJECTS 64
1019         MonoObject *to_finalize [NUM_FOBJECTS];
1020         int count;
1021 #endif
1022
1023         /* Process finalizers which are already in the queue */
1024         mono_gc_invoke_finalizers ();
1025
1026 #ifdef HAVE_BOEHM_GC
1027         while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
1028                 int i;
1029                 GPtrArray *objs;
1030                 /* 
1031                  * Since the domain is unloading, nobody is allowed to put
1032                  * new entries into the hash table. But finalize_object might
1033                  * remove entries from the hash table, so we make a copy.
1034                  */
1035                 objs = g_ptr_array_new ();
1036                 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
1037                 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
1038
1039                 for (i = 0; i < objs->len; ++i) {
1040                         MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
1041                         /* FIXME: Avoid finalizing threads, etc */
1042                         mono_gc_run_finalize (o, 0);
1043                 }
1044
1045                 g_ptr_array_free (objs, TRUE);
1046         }
1047 #elif defined(HAVE_SGEN_GC)
1048         while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
1049                 int i;
1050                 for (i = 0; i < count; ++i) {
1051                         mono_gc_run_finalize (to_finalize [i], 0);
1052                 }
1053         }
1054 #endif
1055
1056         /* cleanup the reference queue */
1057         reference_queue_clear_for_domain (domain);
1058         
1059         /* printf ("DONE.\n"); */
1060         SetEvent (req->done_event);
1061
1062         /* The event is closed in mono_domain_finalize if we get here */
1063         g_free (req);
1064 }
1065
1066 static guint32
1067 finalizer_thread (gpointer unused)
1068 {
1069         while (!finished) {
1070                 /* Wait to be notified that there's at least one
1071                  * finaliser to run
1072                  */
1073
1074                 g_assert (mono_domain_get () == mono_get_root_domain ());
1075
1076                 /* An alertable wait is required so this thread can be suspended on windows */
1077 #ifdef MONO_HAS_SEMAPHORES
1078                 MONO_SEM_WAIT_ALERTABLE (&finalizer_sem, TRUE);
1079 #else
1080                 WaitForSingleObjectEx (finalizer_event, INFINITE, TRUE);
1081 #endif
1082
1083                 mono_threads_perform_thread_dump ();
1084
1085                 mono_console_handle_async_ops ();
1086
1087 #ifndef DISABLE_ATTACH
1088                 mono_attach_maybe_start ();
1089 #endif
1090
1091                 if (domains_to_finalize) {
1092                         mono_finalizer_lock ();
1093                         if (domains_to_finalize) {
1094                                 DomainFinalizationReq *req = domains_to_finalize->data;
1095                                 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
1096                                 mono_finalizer_unlock ();
1097
1098                                 finalize_domain_objects (req);
1099                         } else {
1100                                 mono_finalizer_unlock ();
1101                         }
1102                 }                               
1103
1104                 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
1105                  * before the domain is unloaded.
1106                  */
1107                 mono_gc_invoke_finalizers ();
1108
1109                 reference_queue_proccess_all ();
1110
1111                 SetEvent (pending_done_event);
1112         }
1113
1114         SetEvent (shutdown_event);
1115         return 0;
1116 }
1117
1118 #ifndef LAZY_GC_THREAD_CREATION
1119 static
1120 #endif
1121 void
1122 mono_gc_init_finalizer_thread (void)
1123 {
1124         gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, TRUE, 0);
1125         ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
1126 }
1127
1128 void
1129 mono_gc_init (void)
1130 {
1131         InitializeCriticalSection (&handle_section);
1132         InitializeCriticalSection (&allocator_section);
1133
1134         InitializeCriticalSection (&finalizer_mutex);
1135         InitializeCriticalSection (&reference_queue_mutex);
1136
1137         MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
1138         MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
1139
1140         mono_counters_register ("Created object count", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &mono_stats.new_object_count);
1141         mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.minor_gc_count);
1142         mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
1143         mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.minor_gc_time_usecs);
1144         mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.major_gc_time_usecs);
1145
1146         mono_gc_base_init ();
1147
1148         if (mono_gc_is_disabled ()) {
1149                 gc_disabled = TRUE;
1150                 return;
1151         }
1152         
1153         finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1154         pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1155         shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1156         if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL) {
1157                 g_assert_not_reached ();
1158         }
1159 #ifdef MONO_HAS_SEMAPHORES
1160         MONO_SEM_INIT (&finalizer_sem, 0);
1161 #endif
1162
1163 #ifndef LAZY_GC_THREAD_CREATION
1164         mono_gc_init_finalizer_thread ();
1165 #endif
1166 }
1167
1168 void
1169 mono_gc_cleanup (void)
1170 {
1171 #ifdef DEBUG
1172         g_message ("%s: cleaning up finalizer", __func__);
1173 #endif
1174
1175         if (!gc_disabled) {
1176                 ResetEvent (shutdown_event);
1177                 finished = TRUE;
1178                 if (mono_thread_internal_current () != gc_thread) {
1179                         mono_gc_finalize_notify ();
1180                         /* Finishing the finalizer thread, so wait a little bit... */
1181                         /* MS seems to wait for about 2 seconds */
1182                         if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1183                                 int ret;
1184
1185                                 /* Set a flag which the finalizer thread can check */
1186                                 suspend_finalizers = TRUE;
1187
1188                                 /* Try to abort the thread, in the hope that it is running managed code */
1189                                 mono_thread_internal_stop (gc_thread);
1190
1191                                 /* Wait for it to stop */
1192                                 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1193
1194                                 if (ret == WAIT_TIMEOUT) {
1195                                         /* 
1196                                          * The finalizer thread refused to die. There is not much we 
1197                                          * can do here, since the runtime is shutting down so the 
1198                                          * state the finalizer thread depends on will vanish.
1199                                          */
1200                                         g_warning ("Shutting down finalizer thread timed out.");
1201                                 } else {
1202                                         /*
1203                                          * FIXME: On unix, when the above wait returns, the thread 
1204                                          * might still be running io-layer code, or pthreads code.
1205                                          */
1206                                         Sleep (100);
1207                                 }
1208                         } else {
1209                                 int ret;
1210
1211                                 /* Wait for the thread to actually exit */
1212                                 ret = WaitForSingleObjectEx (gc_thread->handle, INFINITE, TRUE);
1213                                 g_assert (ret == WAIT_OBJECT_0);
1214
1215 #ifndef HOST_WIN32
1216                                 /*
1217                                  * The above wait only waits for the exited event to be signalled, the thread might still be running. To fix this race, we
1218                                  * create the finalizer thread without calling pthread_detach () on it, so we can wait for it manually.
1219                                  */
1220                                 ret = pthread_join ((MonoNativeThreadId)(gpointer)(gsize)gc_thread->tid, NULL);
1221                                 g_assert (ret == 0);
1222 #endif
1223                         }
1224                 }
1225                 gc_thread = NULL;
1226 #ifdef HAVE_BOEHM_GC
1227                 GC_finalizer_notifier = NULL;
1228 #endif
1229         }
1230
1231         mono_reference_queue_cleanup ();
1232
1233         DeleteCriticalSection (&handle_section);
1234         DeleteCriticalSection (&allocator_section);
1235         DeleteCriticalSection (&finalizer_mutex);
1236         DeleteCriticalSection (&reference_queue_mutex);
1237 }
1238
1239 #else
1240
1241 /* Null GC dummy functions */
1242 void
1243 mono_gc_finalize_notify (void)
1244 {
1245 }
1246
1247 void mono_gc_init (void)
1248 {
1249         InitializeCriticalSection (&handle_section);
1250 }
1251
1252 void mono_gc_cleanup (void)
1253 {
1254 }
1255
1256 #endif
1257
1258 gboolean
1259 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
1260 {
1261         return thread == gc_thread;
1262 }
1263
1264 /**
1265  * mono_gc_is_finalizer_thread:
1266  * @thread: the thread to test.
1267  *
1268  * In Mono objects are finalized asynchronously on a separate thread.
1269  * This routine tests whether the @thread argument represents the
1270  * finalization thread.
1271  * 
1272  * Returns true if @thread is the finalization thread.
1273  */
1274 gboolean
1275 mono_gc_is_finalizer_thread (MonoThread *thread)
1276 {
1277         return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
1278 }
1279
1280 #if defined(__MACH__)
1281 static pthread_t mach_exception_thread;
1282
1283 void
1284 mono_gc_register_mach_exception_thread (pthread_t thread)
1285 {
1286         mach_exception_thread = thread;
1287 }
1288
1289 pthread_t
1290 mono_gc_get_mach_exception_thread (void)
1291 {
1292         return mach_exception_thread;
1293 }
1294 #endif
1295
1296 /**
1297  * mono_gc_parse_environment_string_extract_number:
1298  *
1299  * @str: points to the first digit of the number
1300  * @out: pointer to the variable that will receive the value
1301  *
1302  * Tries to extract a number from the passed string, taking in to account m, k
1303  * and g suffixes
1304  *
1305  * Returns true if passing was successful
1306  */
1307 gboolean
1308 mono_gc_parse_environment_string_extract_number (const char *str, glong *out)
1309 {
1310         char *endptr;
1311         int len = strlen (str), shift = 0;
1312         glong val;
1313         gboolean is_suffix = FALSE;
1314         char suffix;
1315
1316         if (!len)
1317                 return FALSE;
1318
1319         suffix = str [len - 1];
1320
1321         switch (suffix) {
1322                 case 'g':
1323                 case 'G':
1324                         shift += 10;
1325                 case 'm':
1326                 case 'M':
1327                         shift += 10;
1328                 case 'k':
1329                 case 'K':
1330                         shift += 10;
1331                         is_suffix = TRUE;
1332                         break;
1333                 default:
1334                         if (!isdigit (suffix))
1335                                 return FALSE;
1336                         break;
1337         }
1338
1339         errno = 0;
1340         val = strtol (str, &endptr, 10);
1341
1342         if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
1343                         || (errno != 0 && val == 0) || (endptr == str))
1344                 return FALSE;
1345
1346         if (is_suffix) {
1347                 gulong unshifted;
1348
1349                 if (val < 0)    /* negative numbers cannot be suffixed */
1350                         return FALSE;
1351                 if (*(endptr + 1)) /* Invalid string. */
1352                         return FALSE;
1353
1354                 unshifted = (gulong)val;
1355                 val <<= shift;
1356                 if (val < 0)    /* overflow */
1357                         return FALSE;
1358                 if (((gulong)val >> shift) != unshifted) /* value too large */
1359                         return FALSE;
1360         }
1361
1362         *out = val;
1363         return TRUE;
1364 }
1365
1366 #ifndef HAVE_SGEN_GC
1367 void*
1368 mono_gc_alloc_mature (MonoVTable *vtable)
1369 {
1370         return mono_object_new_specific (vtable);
1371 }
1372 #endif
1373
1374
1375 static MonoReferenceQueue *ref_queues;
1376
1377 static void
1378 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
1379 {
1380         do {
1381                 /* Guard if head is changed concurrently. */
1382                 while (*prev != element)
1383                         prev = &(*prev)->next;
1384         } while (prev && InterlockedCompareExchangePointer ((void*)prev, element->next, element) != element);
1385 }
1386
1387 static void
1388 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
1389 {
1390         RefQueueEntry *current;
1391         do {
1392                 current = *head;
1393                 value->next = current;
1394                 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1395         } while (InterlockedCompareExchangePointer ((void*)head, value, current) != current);
1396 }
1397
1398 static void
1399 reference_queue_proccess (MonoReferenceQueue *queue)
1400 {
1401         RefQueueEntry **iter = &queue->queue;
1402         RefQueueEntry *entry;
1403         while ((entry = *iter)) {
1404 #ifdef HAVE_SGEN_GC
1405                 if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
1406                         mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1407 #else
1408                 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1409                         mono_gchandle_free ((guint32)entry->gchandle);
1410 #endif
1411                         ref_list_remove_element (iter, entry);
1412                         queue->callback (entry->user_data);
1413                         g_free (entry);
1414                 } else {
1415                         iter = &entry->next;
1416                 }
1417         }
1418 }
1419
1420 static void
1421 reference_queue_proccess_all (void)
1422 {
1423         MonoReferenceQueue **iter;
1424         MonoReferenceQueue *queue = ref_queues;
1425         for (; queue; queue = queue->next)
1426                 reference_queue_proccess (queue);
1427
1428 restart:
1429         EnterCriticalSection (&reference_queue_mutex);
1430         for (iter = &ref_queues; *iter;) {
1431                 queue = *iter;
1432                 if (!queue->should_be_deleted) {
1433                         iter = &queue->next;
1434                         continue;
1435                 }
1436                 if (queue->queue) {
1437                         LeaveCriticalSection (&reference_queue_mutex);
1438                         reference_queue_proccess (queue);
1439                         goto restart;
1440                 }
1441                 *iter = queue->next;
1442                 g_free (queue);
1443         }
1444         LeaveCriticalSection (&reference_queue_mutex);
1445 }
1446
1447 static void
1448 mono_reference_queue_cleanup (void)
1449 {
1450         MonoReferenceQueue *queue = ref_queues;
1451         for (; queue; queue = queue->next)
1452                 queue->should_be_deleted = TRUE;
1453         reference_queue_proccess_all ();
1454 }
1455
1456 static void
1457 reference_queue_clear_for_domain (MonoDomain *domain)
1458 {
1459         MonoReferenceQueue *queue = ref_queues;
1460         for (; queue; queue = queue->next) {
1461                 RefQueueEntry **iter = &queue->queue;
1462                 RefQueueEntry *entry;
1463                 while ((entry = *iter)) {
1464                         MonoObject *obj;
1465 #ifdef HAVE_SGEN_GC
1466                         obj = mono_gc_weak_link_get (&entry->dis_link);
1467                         if (obj && mono_object_domain (obj) == domain) {
1468                                 mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1469 #else
1470                         obj = mono_gchandle_get_target (entry->gchandle);
1471                         if (obj && mono_object_domain (obj) == domain) {
1472                                 mono_gchandle_free ((guint32)entry->gchandle);
1473 #endif
1474                                 ref_list_remove_element (iter, entry);
1475                                 queue->callback (entry->user_data);
1476                                 g_free (entry);
1477                         } else {
1478                                 iter = &entry->next;
1479                         }
1480                 }
1481         }
1482 }
1483 /**
1484  * mono_gc_reference_queue_new:
1485  * @callback callback used when processing dead entries.
1486  *
1487  * Create a new reference queue used to process collected objects.
1488  * A reference queue let you queue a pair (managed object, user data)
1489  * using the mono_gc_reference_queue_add method.
1490  *
1491  * Once the managed object is collected @callback will be called
1492  * in the finalizer thread with 'user data' as argument.
1493  *
1494  * The callback is called without any locks held.
1495  */
1496 MonoReferenceQueue*
1497 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1498 {
1499         MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1500         res->callback = callback;
1501
1502         EnterCriticalSection (&reference_queue_mutex);
1503         res->next = ref_queues;
1504         ref_queues = res;
1505         LeaveCriticalSection (&reference_queue_mutex);
1506
1507         return res;
1508 }
1509
1510 /**
1511  * mono_gc_reference_queue_add:
1512  * @queue the queue to add the reference to.
1513  * @obj the object to be watched for collection
1514  * @user_data parameter to be passed to the queue callback
1515  *
1516  * Queue an object to be watched for collection, when the @obj is
1517  * collected, the callback that was registered for the @queue will
1518  * be invoked with the @obj and @user_data arguments.
1519  *
1520  * @returns false if the queue is scheduled to be freed.
1521  */
1522 gboolean
1523 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1524 {
1525         RefQueueEntry *entry;
1526         if (queue->should_be_deleted)
1527                 return FALSE;
1528
1529         entry = g_new0 (RefQueueEntry, 1);
1530         entry->user_data = user_data;
1531
1532 #ifdef HAVE_SGEN_GC
1533         mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
1534 #else
1535         entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1536         mono_object_register_finalizer (obj);
1537 #endif
1538
1539         ref_list_push (&queue->queue, entry);
1540         return TRUE;
1541 }
1542
1543 /**
1544  * mono_gc_reference_queue_free:
1545  * @queue the queue that should be deleted.
1546  *
1547  * This operation signals that @queue should be deleted. This operation is deferred
1548  * as it happens on the finalizer thread.
1549  *
1550  * After this call, no further objects can be queued. It's the responsibility of the
1551  * caller to make sure that no further attempt to access queue will be made.
1552  */
1553 void
1554 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1555 {
1556         queue->should_be_deleted = TRUE;
1557 }
1558
1559 #define ptr_mask ((sizeof (void*) - 1))
1560 #define _toi(ptr) ((size_t)ptr)
1561 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
1562 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
1563 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
1564
1565 #define BZERO_WORDS(dest,words) do {    \
1566         int __i;        \
1567         for (__i = 0; __i < (words); ++__i)     \
1568                 ((void **)(dest))[__i] = 0;     \
1569 } while (0)
1570
1571 /**
1572  * mono_gc_bzero:
1573  * @dest: address to start to clear
1574  * @size: size of the region to clear
1575  *
1576  * Zero @size bytes starting at @dest.
1577  *
1578  * Use this to zero memory that can hold managed pointers.
1579  *
1580  * FIXME borrow faster code from some BSD libc or bionic
1581  */
1582 void
1583 mono_gc_bzero (void *dest, size_t size)
1584 {
1585         char *d = (char*)dest;
1586         size_t tail_bytes, word_bytes;
1587
1588         /*
1589         If we're copying less than a word, just use memset.
1590
1591         We cannot bail out early if both are aligned because some implementations
1592         use byte copying for sizes smaller than 16. OSX, on this case.
1593         */
1594         if (size < sizeof(void*)) {
1595                 memset (dest, 0, size);
1596                 return;
1597         }
1598
1599         /*align to word boundary */
1600         while (unaligned_bytes (d) && size) {
1601                 *d++ = 0;
1602                 --size;
1603         }
1604
1605         /* copy all words with memmove */
1606         word_bytes = (size_t)align_down (size);
1607         switch (word_bytes) {
1608         case sizeof (void*) * 1:
1609                 BZERO_WORDS (d, 1);
1610                 break;
1611         case sizeof (void*) * 2:
1612                 BZERO_WORDS (d, 2);
1613                 break;
1614         case sizeof (void*) * 3:
1615                 BZERO_WORDS (d, 3);
1616                 break;
1617         case sizeof (void*) * 4:
1618                 BZERO_WORDS (d, 4);
1619                 break;
1620         default:
1621                 memset (d, 0, word_bytes);
1622         }
1623
1624         tail_bytes = unaligned_bytes (size);
1625         if (tail_bytes) {
1626                 d += word_bytes;
1627                 do {
1628                         *d++ = 0;
1629                 } while (--tail_bytes);
1630         }
1631 }
1632
1633 /**
1634  * mono_gc_memmove:
1635  * @dest: destination of the move
1636  * @src: source
1637  * @size: size of the block to move
1638  *
1639  * Move @size bytes from @src to @dest.
1640  * size MUST be a multiple of sizeof (gpointer)
1641  *
1642  */
1643 void
1644 mono_gc_memmove (void *dest, const void *src, size_t size)
1645 {
1646         /*
1647         If we're copying less than a word we don't need to worry about word tearing
1648         so we bailout to memmove early.
1649
1650         If both dest is aligned and size is a multiple of word size, we can go straigh
1651         to memmove.
1652
1653         */
1654         if (size < sizeof(void*) || !((_toi (dest) | (size)) & sizeof (void*))) {
1655                 memmove (dest, src, size);
1656                 return;
1657         }
1658
1659         /*
1660          * A bit of explanation on why we align only dest before doing word copies.
1661          * Pointers to managed objects must always be stored in word aligned addresses, so
1662          * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
1663          *
1664          * We don't need to case when source and destination have different alignments since we only do word stores
1665          * using memmove, which must handle it.
1666          */
1667         if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) { /*backward copy*/
1668                 char *p = (char*)dest + size;
1669                         char *s = (char*)src + size;
1670                         char *start = (char*)dest;
1671                         char *align_end = MAX((char*)dest, (char*)align_down (p));
1672                         char *word_start;
1673                         size_t bytes_to_memmove;
1674
1675                         while (p > align_end)
1676                                 *--p = *--s;
1677
1678                         word_start = align_up (start);
1679                         bytes_to_memmove = p - word_start;
1680                         p -= bytes_to_memmove;
1681                         s -= bytes_to_memmove;
1682                         memmove (p, s, bytes_to_memmove);
1683
1684                         while (p > start)
1685                                 *--p = *--s;
1686         } else {
1687                 char *d = (char*)dest;
1688                 const char *s = (const char*)src;
1689                 size_t tail_bytes;
1690
1691                 /*align to word boundary */
1692                 while (unaligned_bytes (d)) {
1693                         *d++ = *s++;
1694                         --size;
1695                 }
1696
1697                 /* copy all words with memmove */
1698                 memmove (d, s, (size_t)align_down (size));
1699
1700                 tail_bytes = unaligned_bytes (size);
1701                 if (tail_bytes) {
1702                         d += (size_t)align_down (size);
1703                         s += (size_t)align_down (size);
1704                         do {
1705                                 *d++ = *s++;
1706                         } while (--tail_bytes);
1707                 }
1708         }
1709 }
1710
1711