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