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