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