Merge pull request #3589 from ntherning/fix-line-ending-issues-in-System.Data-tests
[mono.git] / mono / metadata / boehm-gc.c
1 /*
2  * boehm-gc.c: GC implementation using either the installed or included Boehm GC.
3  *
4  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
5  * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
6  * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
7  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
8  */
9
10 #include "config.h"
11
12 #include <string.h>
13
14 #define GC_I_HIDE_POINTERS
15 #include <mono/metadata/gc-internals.h>
16 #include <mono/metadata/mono-gc.h>
17 #include <mono/metadata/profiler-private.h>
18 #include <mono/metadata/class-internals.h>
19 #include <mono/metadata/method-builder.h>
20 #include <mono/metadata/opcodes.h>
21 #include <mono/metadata/domain-internals.h>
22 #include <mono/metadata/metadata-internals.h>
23 #include <mono/metadata/marshal.h>
24 #include <mono/metadata/runtime.h>
25 #include <mono/metadata/handle.h>
26 #include <mono/metadata/sgen-toggleref.h>
27 #include <mono/utils/atomic.h>
28 #include <mono/utils/mono-logger-internals.h>
29 #include <mono/utils/mono-memory-model.h>
30 #include <mono/utils/mono-time.h>
31 #include <mono/utils/mono-threads.h>
32 #include <mono/utils/dtrace.h>
33 #include <mono/utils/gc_wrapper.h>
34 #include <mono/utils/mono-os-mutex.h>
35 #include <mono/utils/mono-counters.h>
36
37 #if HAVE_BOEHM_GC
38
39 #undef TRUE
40 #undef FALSE
41 #define THREAD_LOCAL_ALLOC 1
42 #include "private/pthread_support.h"
43
44 #if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
45 void *pthread_get_stackaddr_np(pthread_t);
46 #endif
47
48 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
49 /*Boehm max heap cannot be smaller than 16MB*/
50 #define MIN_BOEHM_MAX_HEAP_SIZE_IN_MB 16
51 #define MIN_BOEHM_MAX_HEAP_SIZE (MIN_BOEHM_MAX_HEAP_SIZE_IN_MB << 20)
52
53 static gboolean gc_initialized = FALSE;
54 static mono_mutex_t mono_gc_lock;
55
56 static void*
57 boehm_thread_register (MonoThreadInfo* info, void *baseptr);
58 static void
59 boehm_thread_unregister (MonoThreadInfo *p);
60 static void
61 boehm_thread_detach (MonoThreadInfo *p);
62 static void
63 register_test_toggleref_callback (void);
64
65 #define BOEHM_GC_BIT_FINALIZER_AWARE 1
66 static MonoGCFinalizerCallbacks fin_callbacks;
67
68 /* GC Handles */
69
70 static mono_mutex_t handle_section;
71 #define lock_handles(handles) mono_os_mutex_lock (&handle_section)
72 #define unlock_handles(handles) mono_os_mutex_unlock (&handle_section)
73
74 typedef struct {
75         guint32  *bitmap;
76         gpointer *entries;
77         guint32   size;
78         guint8    type;
79         guint     slot_hint : 24; /* starting slot for search in bitmap */
80         /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
81         /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
82         guint16  *domain_ids;
83 } HandleData;
84
85 #define EMPTY_HANDLE_DATA(type) {NULL, NULL, 0, (type), 0, NULL}
86
87 /* weak and weak-track arrays will be allocated in malloc memory 
88  */
89 static HandleData gc_handles [] = {
90         EMPTY_HANDLE_DATA (HANDLE_WEAK),
91         EMPTY_HANDLE_DATA (HANDLE_WEAK_TRACK),
92         EMPTY_HANDLE_DATA (HANDLE_NORMAL),
93         EMPTY_HANDLE_DATA (HANDLE_PINNED)
94 };
95
96 static void
97 mono_gc_warning (char *msg, GC_word arg)
98 {
99         mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_GC, msg, (unsigned long)arg);
100 }
101
102 void
103 mono_gc_base_init (void)
104 {
105         MonoThreadInfoCallbacks cb;
106         const char *env;
107         int dummy;
108
109         if (gc_initialized)
110                 return;
111
112         mono_counters_init ();
113
114         /*
115          * Handle the case when we are called from a thread different from the main thread,
116          * confusing libgc.
117          * FIXME: Move this to libgc where it belongs.
118          *
119          * we used to do this only when running on valgrind,
120          * but it happens also in other setups.
121          */
122 #if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK) && !defined(__native_client__)
123         {
124                 size_t size;
125                 void *sstart;
126                 pthread_attr_t attr;
127                 pthread_getattr_np (pthread_self (), &attr);
128                 pthread_attr_getstack (&attr, &sstart, &size);
129                 pthread_attr_destroy (&attr); 
130                 /*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/
131 #ifdef __ia64__
132                 /*
133                  * The calculation above doesn't seem to work on ia64, also we need to set
134                  * GC_register_stackbottom as well, but don't know how.
135                  */
136 #else
137                 /* apparently with some linuxthreads implementations sstart can be NULL,
138                  * fallback to the more imprecise method (bug# 78096).
139                  */
140                 if (sstart) {
141                         GC_stackbottom = (char*)sstart + size;
142                 } else {
143                         int dummy;
144                         gsize stack_bottom = (gsize)&dummy;
145                         stack_bottom += 4095;
146                         stack_bottom &= ~4095;
147                         GC_stackbottom = (char*)stack_bottom;
148                 }
149 #endif
150         }
151 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
152                 GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ());
153 #elif defined(__OpenBSD__)
154 #  include <pthread_np.h>
155         {
156                 stack_t ss;
157                 int rslt;
158
159                 rslt = pthread_stackseg_np(pthread_self(), &ss);
160                 g_assert (rslt == 0);
161
162                 GC_stackbottom = (char*)ss.ss_sp;
163         }
164 #elif defined(__native_client__)
165         /* Do nothing, GC_stackbottom is set correctly in libgc */
166 #else
167         {
168                 int dummy;
169                 gsize stack_bottom = (gsize)&dummy;
170                 stack_bottom += 4095;
171                 stack_bottom &= ~4095;
172                 /*g_print ("stackbottom is: %p\n", (char*)stack_bottom);*/
173                 GC_stackbottom = (char*)stack_bottom;
174         }
175 #endif
176
177 #if !defined(PLATFORM_ANDROID)
178         /* If GC_no_dls is set to true, GC_find_limit is not called. This causes a seg fault on Android. */
179         GC_no_dls = TRUE;
180 #endif
181         {
182                 if ((env = g_getenv ("MONO_GC_DEBUG"))) {
183                         char **opts = g_strsplit (env, ",", -1);
184                         for (char **ptr = opts; ptr && *ptr; ptr ++) {
185                                 char *opt = *ptr;
186                                 if (!strcmp (opt, "do-not-finalize")) {
187                                         mono_do_not_finalize = 1;
188                                 } else if (!strcmp (opt, "log-finalizers")) {
189                                         log_finalizers = 1;
190                                 }
191                         }
192                 }
193         }
194
195         GC_init ();
196
197         GC_set_warn_proc (mono_gc_warning);
198         GC_finalize_on_demand = 1;
199         GC_finalizer_notifier = mono_gc_finalize_notify;
200
201         GC_init_gcj_malloc (5, NULL);
202         GC_allow_register_threads ();
203
204         if ((env = g_getenv ("MONO_GC_PARAMS"))) {
205                 char **ptr, **opts = g_strsplit (env, ",", -1);
206                 for (ptr = opts; *ptr; ++ptr) {
207                         char *opt = *ptr;
208                         if (g_str_has_prefix (opt, "max-heap-size=")) {
209                                 size_t max_heap;
210
211                                 opt = strchr (opt, '=') + 1;
212                                 if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap)) {
213                                         if (max_heap < MIN_BOEHM_MAX_HEAP_SIZE) {
214                                                 fprintf (stderr, "max-heap-size must be at least %dMb.\n", MIN_BOEHM_MAX_HEAP_SIZE_IN_MB);
215                                                 exit (1);
216                                         }
217                                         GC_set_max_heap_size (max_heap);
218                                 } else {
219                                         fprintf (stderr, "max-heap-size must be an integer.\n");
220                                         exit (1);
221                                 }
222                                 continue;
223                         } else if (g_str_has_prefix (opt, "toggleref-test")) {
224                                 register_test_toggleref_callback ();
225                                 continue;
226                         } else {
227                                 /* Could be a parameter for sgen */
228                                 /*
229                                 fprintf (stderr, "MONO_GC_PARAMS must be a comma-delimited list of one or more of the following:\n");
230                                 fprintf (stderr, "  max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
231                                 exit (1);
232                                 */
233                         }
234                 }
235                 g_strfreev (opts);
236         }
237
238         memset (&cb, 0, sizeof (cb));
239         cb.thread_register = boehm_thread_register;
240         cb.thread_unregister = boehm_thread_unregister;
241         cb.thread_detach = boehm_thread_detach;
242         cb.mono_method_is_critical = (gboolean (*)(void *))mono_runtime_is_critical_method;
243
244         mono_threads_init (&cb, sizeof (MonoThreadInfo));
245         mono_os_mutex_init (&mono_gc_lock);
246         mono_os_mutex_init_recursive (&handle_section);
247
248         mono_thread_info_attach (&dummy);
249
250         mono_gc_enable_events ();
251
252         MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
253         MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
254
255         gc_initialized = TRUE;
256 }
257
258 void
259 mono_gc_base_cleanup (void)
260 {
261         GC_finalizer_notifier = NULL;
262 }
263
264 /**
265  * mono_gc_collect:
266  * @generation: GC generation identifier
267  *
268  * Perform a garbage collection for the given generation, higher numbers
269  * mean usually older objects. Collecting a high-numbered generation
270  * implies collecting also the lower-numbered generations.
271  * The maximum value for @generation can be retrieved with a call to
272  * mono_gc_max_generation(), so this function is usually called as:
273  *
274  *      mono_gc_collect (mono_gc_max_generation ());
275  */
276 void
277 mono_gc_collect (int generation)
278 {
279 #ifndef DISABLE_PERFCOUNTERS
280         mono_perfcounters->gc_induced++;
281 #endif
282         GC_gcollect ();
283 }
284
285 /**
286  * mono_gc_max_generation:
287  *
288  * Get the maximum generation number used by the current garbage
289  * collector. The value will be 0 for the Boehm collector, 1 or more
290  * for the generational collectors.
291  *
292  * Returns: the maximum generation number.
293  */
294 int
295 mono_gc_max_generation (void)
296 {
297         return 0;
298 }
299
300 /**
301  * mono_gc_get_generation:
302  * @object: a managed object
303  *
304  * Get the garbage collector's generation that @object belongs to.
305  * Use this has a hint only.
306  *
307  * Returns: a garbage collector generation number
308  */
309 int
310 mono_gc_get_generation  (MonoObject *object)
311 {
312         return 0;
313 }
314
315 /**
316  * mono_gc_collection_count:
317  * @generation: a GC generation number
318  *
319  * Get how many times a garbage collection has been performed
320  * for the given @generation number.
321  *
322  * Returns: the number of garbage collections
323  */
324 int
325 mono_gc_collection_count (int generation)
326 {
327         return GC_gc_no;
328 }
329
330 /**
331  * mono_gc_add_memory_pressure:
332  * @value: amount of bytes
333  *
334  * Adjust the garbage collector's view of how many bytes of memory
335  * are indirectly referenced by managed objects (for example unmanaged
336  * memory holding image or other binary data).
337  * This is a hint only to the garbage collector algorithm.
338  * Note that negative amounts of @value will decrease the memory
339  * pressure.
340  */
341 void
342 mono_gc_add_memory_pressure (gint64 value)
343 {
344 }
345
346 /**
347  * mono_gc_get_used_size:
348  *
349  * Get the approximate amount of memory used by managed objects.
350  *
351  * Returns: the amount of memory used in bytes
352  */
353 int64_t
354 mono_gc_get_used_size (void)
355 {
356         return GC_get_heap_size () - GC_get_free_bytes ();
357 }
358
359 /**
360  * mono_gc_get_heap_size:
361  *
362  * Get the amount of memory used by the garbage collector.
363  *
364  * Returns: the size of the heap in bytes
365  */
366 int64_t
367 mono_gc_get_heap_size (void)
368 {
369         return GC_get_heap_size ();
370 }
371
372 gboolean
373 mono_gc_is_gc_thread (void)
374 {
375         return GC_thread_is_registered ();
376 }
377
378 gboolean
379 mono_gc_register_thread (void *baseptr)
380 {
381         return mono_thread_info_attach (baseptr) != NULL;
382 }
383
384 static void*
385 boehm_thread_register (MonoThreadInfo* info, void *baseptr)
386 {
387         struct GC_stack_base sb;
388         int res;
389
390         /* TODO: use GC_get_stack_base instead of baseptr. */
391         sb.mem_base = baseptr;
392         res = GC_register_my_thread (&sb);
393         if (res == GC_UNIMPLEMENTED)
394             return NULL; /* Cannot happen with GC v7+. */
395
396         info->handle_stack = mono_handle_stack_alloc ();
397
398         return info;
399 }
400
401 static void
402 boehm_thread_unregister (MonoThreadInfo *p)
403 {
404         MonoNativeThreadId tid;
405
406         tid = mono_thread_info_get_tid (p);
407
408         if (p->runtime_thread)
409                 mono_threads_add_joinable_thread ((gpointer)tid);
410 }
411
412 static void
413 boehm_thread_detach (MonoThreadInfo *p)
414 {
415         if (mono_thread_internal_current_is_attached ())
416                 mono_thread_detach_internal (mono_thread_internal_current ());
417 }
418
419 gboolean
420 mono_object_is_alive (MonoObject* o)
421 {
422         return GC_is_marked ((ptr_t)o);
423 }
424
425 int
426 mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
427 {
428         return 1;
429 }
430
431 static gint64 gc_start_time;
432
433 static void
434 on_gc_notification (GC_EventType event)
435 {
436         MonoGCEvent e = (MonoGCEvent)event;
437
438         switch (e) {
439         case MONO_GC_EVENT_PRE_STOP_WORLD:
440                 MONO_GC_WORLD_STOP_BEGIN ();
441                 break;
442
443         case MONO_GC_EVENT_POST_STOP_WORLD:
444                 MONO_GC_WORLD_STOP_END ();
445                 break;
446
447         case MONO_GC_EVENT_PRE_START_WORLD:
448                 MONO_GC_WORLD_RESTART_BEGIN (1);
449                 break;
450
451         case MONO_GC_EVENT_POST_START_WORLD:
452                 MONO_GC_WORLD_RESTART_END (1);
453                 break;
454
455         case MONO_GC_EVENT_START:
456                 MONO_GC_BEGIN (1);
457 #ifndef DISABLE_PERFCOUNTERS
458                 if (mono_perfcounters)
459                         mono_perfcounters->gc_collections0++;
460 #endif
461                 gc_stats.major_gc_count ++;
462                 gc_start_time = mono_100ns_ticks ();
463                 break;
464
465         case MONO_GC_EVENT_END:
466                 MONO_GC_END (1);
467 #if defined(ENABLE_DTRACE) && defined(__sun__)
468                 /* This works around a dtrace -G problem on Solaris.
469                    Limit its actual use to when the probe is enabled. */
470                 if (MONO_GC_END_ENABLED ())
471                         sleep(0);
472 #endif
473
474 #ifndef DISABLE_PERFCOUNTERS
475                 if (mono_perfcounters) {
476                         guint64 heap_size = GC_get_heap_size ();
477                         guint64 used_size = heap_size - GC_get_free_bytes ();
478                         mono_perfcounters->gc_total_bytes = used_size;
479                         mono_perfcounters->gc_committed_bytes = heap_size;
480                         mono_perfcounters->gc_reserved_bytes = heap_size;
481                         mono_perfcounters->gc_gen0size = heap_size;
482                 }
483 #endif
484                 gc_stats.major_gc_time += mono_100ns_ticks () - gc_start_time;
485                 mono_trace_message (MONO_TRACE_GC, "gc took %d usecs", (mono_100ns_ticks () - gc_start_time) / 10);
486                 break;
487         default:
488                 break;
489         }
490
491         mono_profiler_gc_event (e, 0);
492
493         switch (e) {
494         case MONO_GC_EVENT_PRE_STOP_WORLD:
495                 mono_thread_info_suspend_lock ();
496                 mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0);
497                 break;
498         case MONO_GC_EVENT_POST_START_WORLD:
499                 mono_thread_info_suspend_unlock ();
500                 mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0);
501                 break;
502         default:
503                 break;
504         }
505 }
506
507  
508 static void
509 on_gc_heap_resize (size_t new_size)
510 {
511         guint64 heap_size = GC_get_heap_size ();
512 #ifndef DISABLE_PERFCOUNTERS
513         if (mono_perfcounters) {
514                 mono_perfcounters->gc_committed_bytes = heap_size;
515                 mono_perfcounters->gc_reserved_bytes = heap_size;
516                 mono_perfcounters->gc_gen0size = heap_size;
517         }
518 #endif
519         mono_profiler_gc_heap_resize (new_size);
520 }
521
522 void
523 mono_gc_enable_events (void)
524 {
525         GC_set_on_collection_event (on_gc_notification);
526         GC_on_heap_resize = on_gc_heap_resize;
527 }
528
529 static gboolean alloc_events = FALSE;
530
531 void
532 mono_gc_enable_alloc_events (void)
533 {
534         alloc_events = TRUE;
535 }
536
537 int
538 mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg)
539 {
540         /* for some strange reason, they want one extra byte on the end */
541         GC_add_roots (start, start + size + 1);
542
543         return TRUE;
544 }
545
546 void
547 mono_gc_deregister_root (char* addr)
548 {
549 #ifndef HOST_WIN32
550         /* FIXME: libgc doesn't define this work win32 for some reason */
551         /* FIXME: No size info */
552         GC_remove_roots (addr, addr + sizeof (gpointer) + 1);
553 #endif
554 }
555
556 static void
557 mono_gc_weak_link_add (void **link_addr, MonoObject *obj, gboolean track)
558 {
559         /* libgc requires that we use HIDE_POINTER... */
560         *link_addr = (void*)HIDE_POINTER (obj);
561         if (track)
562                 GC_REGISTER_LONG_LINK (link_addr, obj);
563         else
564                 GC_GENERAL_REGISTER_DISAPPEARING_LINK (link_addr, obj);
565 }
566
567 static void
568 mono_gc_weak_link_remove (void **link_addr, gboolean track)
569 {
570         if (track)
571                 GC_unregister_long_link (link_addr);
572         else
573                 GC_unregister_disappearing_link (link_addr);
574         *link_addr = NULL;
575 }
576
577 static gpointer
578 reveal_link (gpointer link_addr)
579 {
580         void **link_a = (void **)link_addr;
581         return REVEAL_POINTER (*link_a);
582 }
583
584 static MonoObject *
585 mono_gc_weak_link_get (void **link_addr)
586 {
587         MonoObject *obj = (MonoObject *)GC_call_with_alloc_lock (reveal_link, link_addr);
588         if (obj == (MonoObject *) -1)
589                 return NULL;
590         return obj;
591 }
592
593 void*
594 mono_gc_make_descr_for_string (gsize *bitmap, int numbits)
595 {
596         return mono_gc_make_descr_from_bitmap (bitmap, numbits);
597 }
598
599 void*
600 mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
601 {
602         return mono_gc_make_descr_from_bitmap (bitmap, numbits);
603 }
604
605 void*
606 mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size)
607 {
608         /* libgc has no usable support for arrays... */
609         return GC_NO_DESCRIPTOR;
610 }
611
612 void*
613 mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits)
614 {
615         /* It seems there are issues when the bitmap doesn't fit: play it safe */
616         if (numbits >= 30)
617                 return GC_NO_DESCRIPTOR;
618         else
619                 return (gpointer)GC_make_descriptor ((GC_bitmap)bitmap, numbits);
620 }
621
622 void*
623 mono_gc_make_root_descr_all_refs (int numbits)
624 {
625         return NULL;
626 }
627
628 void*
629 mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, const char *msg)
630 {
631         /* To help track down typed allocation bugs */
632         /*
633         static int count;
634         count ++;
635         if (count == atoi (g_getenv ("COUNT2")))
636                 printf ("HIT!\n");
637         if (count > atoi (g_getenv ("COUNT2")))
638                 return GC_MALLOC (size);
639         */
640
641         if (descr)
642                 return GC_MALLOC_EXPLICITLY_TYPED (size, (GC_descr)descr);
643         else
644                 return GC_MALLOC (size);
645 }
646
647 void
648 mono_gc_free_fixed (void* addr)
649 {
650 }
651
652 void *
653 mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
654 {
655         MonoObject *obj;
656
657         if (!vtable->klass->has_references) {
658                 obj = (MonoObject *)GC_MALLOC_ATOMIC (size);
659                 if (G_UNLIKELY (!obj))
660                         return NULL;
661
662                 obj->vtable = vtable;
663                 obj->synchronisation = NULL;
664
665                 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
666         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
667                 obj = (MonoObject *)GC_GCJ_MALLOC (size, vtable);
668                 if (G_UNLIKELY (!obj))
669                         return NULL;
670         } else {
671                 obj = (MonoObject *)GC_MALLOC (size);
672                 if (G_UNLIKELY (!obj))
673                         return NULL;
674
675                 obj->vtable = vtable;
676         }
677
678         if (G_UNLIKELY (alloc_events))
679                 mono_profiler_allocation (obj);
680
681         return obj;
682 }
683
684 void *
685 mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
686 {
687         MonoArray *obj;
688
689         if (!vtable->klass->has_references) {
690                 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
691                 if (G_UNLIKELY (!obj))
692                         return NULL;
693
694                 obj->obj.vtable = vtable;
695                 obj->obj.synchronisation = NULL;
696
697                 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
698         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
699                 obj = (MonoArray *)GC_GCJ_MALLOC (size, vtable);
700                 if (G_UNLIKELY (!obj))
701                         return NULL;
702         } else {
703                 obj = (MonoArray *)GC_MALLOC (size);
704                 if (G_UNLIKELY (!obj))
705                         return NULL;
706
707                 obj->obj.vtable = vtable;
708         }
709
710         obj->max_length = max_length;
711
712         if (G_UNLIKELY (alloc_events))
713                 mono_profiler_allocation (&obj->obj);
714
715         return obj;
716 }
717
718 void *
719 mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uintptr_t bounds_size)
720 {
721         MonoArray *obj;
722
723         if (!vtable->klass->has_references) {
724                 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
725                 if (G_UNLIKELY (!obj))
726                         return NULL;
727
728                 obj->obj.vtable = vtable;
729                 obj->obj.synchronisation = NULL;
730
731                 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
732         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
733                 obj = (MonoArray *)GC_GCJ_MALLOC (size, vtable);
734                 if (G_UNLIKELY (!obj))
735                         return NULL;
736         } else {
737                 obj = (MonoArray *)GC_MALLOC (size);
738                 if (G_UNLIKELY (!obj))
739                         return NULL;
740
741                 obj->obj.vtable = vtable;
742         }
743
744         obj->max_length = max_length;
745
746         if (bounds_size)
747                 obj->bounds = (MonoArrayBounds *) ((char *) obj + size - bounds_size);
748
749         if (G_UNLIKELY (alloc_events))
750                 mono_profiler_allocation (&obj->obj);
751
752         return obj;
753 }
754
755 void *
756 mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
757 {
758         MonoString *obj = (MonoString *)GC_MALLOC_ATOMIC (size);
759         if (G_UNLIKELY (!obj))
760                 return NULL;
761
762         obj->object.vtable = vtable;
763         obj->object.synchronisation = NULL;
764         obj->length = len;
765         obj->chars [len] = 0;
766
767         if (G_UNLIKELY (alloc_events))
768                 mono_profiler_allocation (&obj->object);
769
770         return obj;
771 }
772
773 void*
774 mono_gc_alloc_mature (MonoVTable *vtable, size_t size)
775 {
776         return mono_gc_alloc_obj (vtable, size);
777 }
778
779 void*
780 mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size)
781 {
782         return mono_gc_alloc_obj (vtable, size);
783 }
784
785 int
786 mono_gc_invoke_finalizers (void)
787 {
788         /* There is a bug in GC_invoke_finalizer () in versions <= 6.2alpha4:
789          * the 'mem_freed' variable is not initialized when there are no
790          * objects to finalize, which leads to strange behavior later on.
791          * The check is necessary to work around that bug.
792          */
793         if (GC_should_invoke_finalizers ())
794                 return GC_invoke_finalizers ();
795         return 0;
796 }
797
798 MonoBoolean
799 mono_gc_pending_finalizers (void)
800 {
801         return GC_should_invoke_finalizers ();
802 }
803
804 void
805 mono_gc_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* value)
806 {
807         *(void**)field_ptr = value;
808 }
809
810 void
811 mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* value)
812 {
813         *(void**)slot_ptr = value;
814 }
815
816 void
817 mono_gc_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
818 {
819         mono_gc_memmove_aligned (dest_ptr, src_ptr, count * sizeof (gpointer));
820 }
821
822 void
823 mono_gc_wbarrier_generic_store (gpointer ptr, MonoObject* value)
824 {
825         *(void**)ptr = value;
826 }
827
828 void
829 mono_gc_wbarrier_generic_store_atomic (gpointer ptr, MonoObject *value)
830 {
831         InterlockedWritePointer ((volatile gpointer *)ptr, value);
832 }
833
834 void
835 mono_gc_wbarrier_generic_nostore (gpointer ptr)
836 {
837 }
838
839 void
840 mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass)
841 {
842         mono_gc_memmove_atomic (dest, src, count * mono_class_value_size (klass, NULL));
843 }
844
845 void
846 mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
847 {
848         /* do not copy the sync state */
849         mono_gc_memmove_aligned ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject),
850                         mono_object_class (obj)->instance_size - sizeof (MonoObject));
851 }
852
853 void
854 mono_gc_clear_domain (MonoDomain *domain)
855 {
856 }
857
858 void
859 mono_gc_suspend_finalizers (void)
860 {
861 }
862
863 int
864 mono_gc_get_suspend_signal (void)
865 {
866         return GC_get_suspend_signal ();
867 }
868
869 int
870 mono_gc_get_restart_signal (void)
871 {
872         return GC_get_thr_restart_signal ();
873 }
874
875 #if defined(USE_COMPILER_TLS) && defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
876 extern __thread MONO_TLS_FAST void* GC_thread_tls;
877 #include "metadata-internals.h"
878
879 static int
880 shift_amount (int v)
881 {
882         int i = 0;
883         while (!(v & (1 << i)))
884                 i++;
885         return i;
886 }
887
888 enum {
889         ATYPE_FREEPTR,
890         ATYPE_FREEPTR_FOR_BOX,
891         ATYPE_NORMAL,
892         ATYPE_GCJ,
893         ATYPE_STRING,
894         ATYPE_NUM
895 };
896
897 static MonoMethod*
898 create_allocator (int atype, int tls_key, gboolean slowpath)
899 {
900         int index_var, bytes_var, my_fl_var, my_entry_var;
901         guint32 no_freelist_branch, not_small_enough_branch = 0;
902         guint32 size_overflow_branch = 0;
903         MonoMethodBuilder *mb;
904         MonoMethod *res;
905         MonoMethodSignature *csig;
906         const char *name = NULL;
907         WrapperInfo *info;
908
909         if (atype == ATYPE_FREEPTR) {
910                 name = slowpath ? "SlowAllocPtrfree" : "AllocPtrfree";
911         } else if (atype == ATYPE_FREEPTR_FOR_BOX) {
912                 name = slowpath ? "SlowAllocPtrfreeBox" : "AllocPtrfreeBox";
913         } else if (atype == ATYPE_NORMAL) {
914                 name = slowpath ? "SlowAlloc" : "Alloc";
915         } else if (atype == ATYPE_GCJ) {
916                 name = slowpath ? "SlowAllocGcj" : "AllocGcj";
917         } else if (atype == ATYPE_STRING) {
918                 name = slowpath ? "SlowAllocString" : "AllocString";
919         } else {
920                 g_assert_not_reached ();
921         }
922
923         csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
924
925         if (atype == ATYPE_STRING) {
926                 csig->ret = &mono_defaults.string_class->byval_arg;
927                 csig->params [0] = &mono_defaults.int_class->byval_arg;
928                 csig->params [1] = &mono_defaults.int32_class->byval_arg;
929         } else {
930                 csig->ret = &mono_defaults.object_class->byval_arg;
931                 csig->params [0] = &mono_defaults.int_class->byval_arg;
932                 csig->params [1] = &mono_defaults.int32_class->byval_arg;
933         }
934
935         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ALLOC);
936
937         if (slowpath)
938                 goto always_slowpath;
939
940         bytes_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
941         if (atype == ATYPE_STRING) {
942                 /* a string alloator method takes the args: (vtable, len) */
943                 /* bytes = (offsetof (MonoString, chars) + ((len + 1) * 2)); */
944                 mono_mb_emit_ldarg (mb, 1);
945                 mono_mb_emit_icon (mb, 1);
946                 mono_mb_emit_byte (mb, MONO_CEE_ADD);
947                 mono_mb_emit_icon (mb, 1);
948                 mono_mb_emit_byte (mb, MONO_CEE_SHL);
949                 // sizeof (MonoString) might include padding
950                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoString, chars));
951                 mono_mb_emit_byte (mb, MONO_CEE_ADD);
952                 mono_mb_emit_stloc (mb, bytes_var);
953         } else {
954                 mono_mb_emit_ldarg (mb, 1);
955                 mono_mb_emit_stloc (mb, bytes_var);
956         }
957
958         /* this is needed for strings/arrays only as the other big types are never allocated with this method */
959         if (atype == ATYPE_STRING) {
960                 /* check for size */
961                 /* if (!SMALL_ENOUGH (bytes)) jump slow_path;*/
962                 mono_mb_emit_ldloc (mb, bytes_var);
963                 mono_mb_emit_icon (mb, (NFREELISTS-1) * GRANULARITY);
964                 not_small_enough_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BGT_UN_S);
965                 /* check for overflow */
966                 mono_mb_emit_ldloc (mb, bytes_var);
967                 mono_mb_emit_icon (mb, sizeof (MonoString));
968                 size_overflow_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLE_UN_S);
969         }
970
971         /* int index = INDEX_FROM_BYTES(bytes); */
972         index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
973         
974         mono_mb_emit_ldloc (mb, bytes_var);
975         mono_mb_emit_icon (mb, GRANULARITY - 1);
976         mono_mb_emit_byte (mb, MONO_CEE_ADD);
977         mono_mb_emit_icon (mb, shift_amount (GRANULARITY));
978         mono_mb_emit_byte (mb, MONO_CEE_SHR_UN);
979         mono_mb_emit_icon (mb, shift_amount (sizeof (gpointer)));
980         mono_mb_emit_byte (mb, MONO_CEE_SHL);
981         /* index var is already adjusted into bytes */
982         mono_mb_emit_stloc (mb, index_var);
983
984         my_fl_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
985         my_entry_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
986         /* my_fl = ((GC_thread)tsd) -> ptrfree_freelists + index; */
987         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
988         mono_mb_emit_byte (mb, 0x0D); /* CEE_MONO_TLS */
989         mono_mb_emit_i4 (mb, tls_key);
990         if (atype == ATYPE_FREEPTR || atype == ATYPE_FREEPTR_FOR_BOX || atype == ATYPE_STRING)
991                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
992                                         + G_STRUCT_OFFSET (struct thread_local_freelists,
993                                                            ptrfree_freelists));
994         else if (atype == ATYPE_NORMAL)
995                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
996                                         + G_STRUCT_OFFSET (struct thread_local_freelists,
997                                                            normal_freelists));
998         else if (atype == ATYPE_GCJ)
999                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
1000                                         + G_STRUCT_OFFSET (struct thread_local_freelists,
1001                                                            gcj_freelists));
1002         else
1003                 g_assert_not_reached ();
1004         mono_mb_emit_byte (mb, MONO_CEE_ADD);
1005         mono_mb_emit_ldloc (mb, index_var);
1006         mono_mb_emit_byte (mb, MONO_CEE_ADD);
1007         mono_mb_emit_stloc (mb, my_fl_var);
1008
1009         /* my_entry = *my_fl; */
1010         mono_mb_emit_ldloc (mb, my_fl_var);
1011         mono_mb_emit_byte (mb, MONO_CEE_LDIND_I);
1012         mono_mb_emit_stloc (mb, my_entry_var);
1013
1014         /* if (EXPECT((word)my_entry >= HBLKSIZE, 1)) { */
1015         mono_mb_emit_ldloc (mb, my_entry_var);
1016         mono_mb_emit_icon (mb, HBLKSIZE);
1017         no_freelist_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLT_UN_S);
1018
1019         /* ptr_t next = obj_link(my_entry); *my_fl = next; */
1020         mono_mb_emit_ldloc (mb, my_fl_var);
1021         mono_mb_emit_ldloc (mb, my_entry_var);
1022         mono_mb_emit_byte (mb, MONO_CEE_LDIND_I);
1023         mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1024
1025         /* set the vtable and clear the words in the object */
1026         mono_mb_emit_ldloc (mb, my_entry_var);
1027         mono_mb_emit_ldarg (mb, 0);
1028         mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1029
1030         if (atype == ATYPE_FREEPTR) {
1031                 int start_var, end_var, start_loop;
1032                 /* end = my_entry + bytes; start = my_entry + sizeof (gpointer);
1033                  */
1034                 start_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1035                 end_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1036                 mono_mb_emit_ldloc (mb, my_entry_var);
1037                 mono_mb_emit_ldloc (mb, bytes_var);
1038                 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1039                 mono_mb_emit_stloc (mb, end_var);
1040                 mono_mb_emit_ldloc (mb, my_entry_var);
1041                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoObject, synchronisation));
1042                 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1043                 mono_mb_emit_stloc (mb, start_var);
1044                 /*
1045                  * do {
1046                  *      *start++ = NULL;
1047                  * } while (start < end);
1048                  */
1049                 start_loop = mono_mb_get_label (mb);
1050                 mono_mb_emit_ldloc (mb, start_var);
1051                 mono_mb_emit_icon (mb, 0);
1052                 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1053                 mono_mb_emit_ldloc (mb, start_var);
1054                 mono_mb_emit_icon (mb, sizeof (gpointer));
1055                 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1056                 mono_mb_emit_stloc (mb, start_var);
1057
1058                 mono_mb_emit_ldloc (mb, start_var);
1059                 mono_mb_emit_ldloc (mb, end_var);
1060                 mono_mb_emit_byte (mb, MONO_CEE_BLT_UN_S);
1061                 mono_mb_emit_byte (mb, start_loop - (mono_mb_get_label (mb) + 1));
1062         } else if (atype == ATYPE_FREEPTR_FOR_BOX || atype == ATYPE_STRING) {
1063                 /* need to clear just the sync pointer */
1064                 mono_mb_emit_ldloc (mb, my_entry_var);
1065                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoObject, synchronisation));
1066                 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1067                 mono_mb_emit_icon (mb, 0);
1068                 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1069         }
1070
1071         if (atype == ATYPE_STRING) {
1072                 /* need to set length and clear the last char */
1073                 /* s->length = len; */
1074                 mono_mb_emit_ldloc (mb, my_entry_var);
1075                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoString, length));
1076                 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1077                 mono_mb_emit_ldarg (mb, 1);
1078                 mono_mb_emit_byte (mb, MONO_CEE_STIND_I4);
1079                 /* s->chars [len] = 0; */
1080                 mono_mb_emit_ldloc (mb, my_entry_var);
1081                 mono_mb_emit_ldloc (mb, bytes_var);
1082                 mono_mb_emit_icon (mb, 2);
1083                 mono_mb_emit_byte (mb, MONO_CEE_SUB);
1084                 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1085                 mono_mb_emit_icon (mb, 0);
1086                 mono_mb_emit_byte (mb, MONO_CEE_STIND_I2);
1087         }
1088
1089         /* return my_entry; */
1090         mono_mb_emit_ldloc (mb, my_entry_var);
1091         mono_mb_emit_byte (mb, MONO_CEE_RET);
1092         
1093         mono_mb_patch_short_branch (mb, no_freelist_branch);
1094         if (not_small_enough_branch > 0)
1095                 mono_mb_patch_short_branch (mb, not_small_enough_branch);
1096         if (size_overflow_branch > 0)
1097                 mono_mb_patch_short_branch (mb, size_overflow_branch);
1098
1099         /* the slow path: we just call back into the runtime */
1100  always_slowpath:
1101         if (atype == ATYPE_STRING) {
1102                 mono_mb_emit_ldarg (mb, 1);
1103                 mono_mb_emit_icall (mb, ves_icall_string_alloc);
1104         } else {
1105                 mono_mb_emit_ldarg (mb, 0);
1106                 mono_mb_emit_icall (mb, ves_icall_object_new_specific);
1107         }
1108
1109         mono_mb_emit_byte (mb, MONO_CEE_RET);
1110
1111         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1112         info->d.alloc.gc_name = "boehm";
1113         info->d.alloc.alloc_type = atype;
1114         mb->init_locals = FALSE;
1115
1116         res = mono_mb_create (mb, csig, 8, info);
1117         mono_mb_free (mb);
1118
1119         return res;
1120 }
1121
1122 static MonoMethod* alloc_method_cache [ATYPE_NUM];
1123 static MonoMethod* slowpath_alloc_method_cache [ATYPE_NUM];
1124
1125 static G_GNUC_UNUSED gboolean
1126 mono_gc_is_critical_method (MonoMethod *method)
1127 {
1128         int i;
1129
1130         for (i = 0; i < ATYPE_NUM; ++i)
1131                 if (method == alloc_method_cache [i] || method == slowpath_alloc_method_cache [i])
1132                         return TRUE;
1133
1134         return FALSE;
1135 }
1136
1137 /*
1138  * If possible, generate a managed method that can quickly allocate objects in class
1139  * @klass. The method will typically have an thread-local inline allocation sequence.
1140  * The signature of the called method is:
1141  *      object allocate (MonoVTable *vtable)
1142  * Some of the logic here is similar to mono_class_get_allocation_ftn () i object.c,
1143  * keep in sync.
1144  * The thread local alloc logic is taken from libgc/pthread_support.c.
1145  */
1146
1147 MonoMethod*
1148 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1149 {
1150         int offset = -1;
1151         int atype;
1152         MONO_THREAD_VAR_OFFSET (GC_thread_tls, offset);
1153
1154         /*g_print ("thread tls: %d\n", offset);*/
1155         if (offset == -1)
1156                 return NULL;
1157         if (!SMALL_ENOUGH (klass->instance_size))
1158                 return NULL;
1159         if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass))
1160                 return NULL;
1161         if (mono_profiler_get_events () & (MONO_PROFILE_ALLOCATIONS | MONO_PROFILE_STATISTICAL))
1162                 return NULL;
1163         if (klass->rank)
1164                 return NULL;
1165         if (mono_class_is_open_constructed_type (&klass->byval_arg))
1166                 return NULL;
1167         if (klass->byval_arg.type == MONO_TYPE_STRING) {
1168                 atype = ATYPE_STRING;
1169         } else if (!known_instance_size) {
1170                 return NULL;
1171         } else if (!klass->has_references) {
1172                 if (for_box)
1173                         atype = ATYPE_FREEPTR_FOR_BOX;
1174                 else
1175                         atype = ATYPE_FREEPTR;
1176         } else {
1177                 return NULL;
1178                 /*
1179                  * disabled because we currently do a runtime choice anyway, to
1180                  * deal with multiple appdomains.
1181                 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1182                         atype = ATYPE_GCJ;
1183                 else
1184                         atype = ATYPE_NORMAL;
1185                 */
1186         }
1187         return mono_gc_get_managed_allocator_by_type (atype, MANAGED_ALLOCATOR_REGULAR);
1188 }
1189
1190 MonoMethod*
1191 mono_gc_get_managed_array_allocator (MonoClass *klass)
1192 {
1193         return NULL;
1194 }
1195
1196 /**
1197  * mono_gc_get_managed_allocator_by_type:
1198  *
1199  *   Return a managed allocator method corresponding to allocator type ATYPE.
1200  */
1201 MonoMethod*
1202 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1203 {
1204         int offset = -1;
1205         MonoMethod *res;
1206         gboolean slowpath = variant != MANAGED_ALLOCATOR_REGULAR;
1207         MonoMethod **cache = slowpath ? slowpath_alloc_method_cache : alloc_method_cache;
1208         MONO_THREAD_VAR_OFFSET (GC_thread_tls, offset);
1209
1210         mono_tls_key_set_offset (TLS_KEY_BOEHM_GC_THREAD, offset);
1211
1212         res = cache [atype];
1213         if (res)
1214                 return res;
1215
1216         res = create_allocator (atype, TLS_KEY_BOEHM_GC_THREAD, slowpath);
1217         mono_os_mutex_lock (&mono_gc_lock);
1218         if (cache [atype]) {
1219                 mono_free_method (res);
1220                 res = cache [atype];
1221         } else {
1222                 mono_memory_barrier ();
1223                 cache [atype] = res;
1224         }
1225         mono_os_mutex_unlock (&mono_gc_lock);
1226         return res;
1227 }
1228
1229 guint32
1230 mono_gc_get_managed_allocator_types (void)
1231 {
1232         return ATYPE_NUM;
1233 }
1234
1235 MonoMethod*
1236 mono_gc_get_write_barrier (void)
1237 {
1238         g_assert_not_reached ();
1239         return NULL;
1240 }
1241
1242 #else
1243
1244 static G_GNUC_UNUSED gboolean
1245 mono_gc_is_critical_method (MonoMethod *method)
1246 {
1247         return FALSE;
1248 }
1249
1250 MonoMethod*
1251 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1252 {
1253         return NULL;
1254 }
1255
1256 MonoMethod*
1257 mono_gc_get_managed_array_allocator (MonoClass *klass)
1258 {
1259         return NULL;
1260 }
1261
1262 MonoMethod*
1263 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1264 {
1265         return NULL;
1266 }
1267
1268 guint32
1269 mono_gc_get_managed_allocator_types (void)
1270 {
1271         return 0;
1272 }
1273
1274 MonoMethod*
1275 mono_gc_get_write_barrier (void)
1276 {
1277         g_assert_not_reached ();
1278         return NULL;
1279 }
1280
1281 #endif
1282
1283 MonoMethod*
1284 mono_gc_get_specific_write_barrier (gboolean is_concurrent)
1285 {
1286         g_assert_not_reached ();
1287         return NULL;
1288 }
1289
1290 int
1291 mono_gc_get_aligned_size_for_allocator (int size)
1292 {
1293         return size;
1294 }
1295
1296 const char *
1297 mono_gc_get_gc_name (void)
1298 {
1299         return "boehm";
1300 }
1301
1302 void*
1303 mono_gc_invoke_with_gc_lock (MonoGCLockedCallbackFunc func, void *data)
1304 {
1305         return GC_call_with_alloc_lock (func, data);
1306 }
1307
1308 char*
1309 mono_gc_get_description (void)
1310 {
1311         return g_strdup (DEFAULT_GC_NAME);
1312 }
1313
1314 void
1315 mono_gc_set_desktop_mode (void)
1316 {
1317         GC_dont_expand = 1;
1318 }
1319
1320 gboolean
1321 mono_gc_is_moving (void)
1322 {
1323         return FALSE;
1324 }
1325
1326 gboolean
1327 mono_gc_is_disabled (void)
1328 {
1329         if (GC_dont_gc || g_getenv ("GC_DONT_GC"))
1330                 return TRUE;
1331         else
1332                 return FALSE;
1333 }
1334
1335 void
1336 mono_gc_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, unsigned bitmap)
1337 {
1338         g_assert_not_reached ();
1339 }
1340
1341
1342 guint8*
1343 mono_gc_get_card_table (int *shift_bits, gpointer *card_mask)
1344 {
1345         g_assert_not_reached ();
1346         return NULL;
1347 }
1348
1349 gboolean
1350 mono_gc_card_table_nursery_check (void)
1351 {
1352         g_assert_not_reached ();
1353         return TRUE;
1354 }
1355
1356 void*
1357 mono_gc_get_nursery (int *shift_bits, size_t *size)
1358 {
1359         return NULL;
1360 }
1361
1362 void
1363 mono_gc_set_current_thread_appdomain (MonoDomain *domain)
1364 {
1365 }
1366
1367 gboolean
1368 mono_gc_precise_stack_mark_enabled (void)
1369 {
1370         return FALSE;
1371 }
1372
1373 FILE *
1374 mono_gc_get_logfile (void)
1375 {
1376         return NULL;
1377 }
1378
1379 void
1380 mono_gc_conservatively_scan_area (void *start, void *end)
1381 {
1382         g_assert_not_reached ();
1383 }
1384
1385 void *
1386 mono_gc_scan_object (void *obj, void *gc_data)
1387 {
1388         g_assert_not_reached ();
1389         return NULL;
1390 }
1391
1392 gsize*
1393 mono_gc_get_bitmap_for_descr (void *descr, int *numbits)
1394 {
1395         g_assert_not_reached ();
1396         return NULL;
1397 }
1398
1399 void
1400 mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks)
1401 {
1402 }
1403
1404 void
1405 mono_gc_set_stack_end (void *stack_end)
1406 {
1407 }
1408
1409 void mono_gc_set_skip_thread (gboolean value)
1410 {
1411 }
1412
1413 void
1414 mono_gc_register_for_finalization (MonoObject *obj, void *user_data)
1415 {
1416         guint offset = 0;
1417
1418 #ifndef GC_DEBUG
1419         /* This assertion is not valid when GC_DEBUG is defined */
1420         g_assert (GC_base (obj) == (char*)obj - offset);
1421 #endif
1422
1423         GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, (GC_finalization_proc)user_data, GUINT_TO_POINTER (offset), NULL, NULL);
1424 }
1425
1426 #ifndef HOST_WIN32
1427 int
1428 mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
1429 {
1430         /* it is being replaced by GC_pthread_create on some
1431          * platforms, see libgc/include/gc_pthread_redirects.h */
1432         return pthread_create (new_thread, attr, start_routine, arg);
1433 }
1434 #endif
1435
1436 #ifdef HOST_WIN32
1437 BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reserved)
1438 {
1439         return GC_DllMain (module_handle, reason, reserved);
1440 }
1441 #endif
1442
1443 guint
1444 mono_gc_get_vtable_bits (MonoClass *klass)
1445 {
1446         if (fin_callbacks.is_class_finalization_aware) {
1447                 if (fin_callbacks.is_class_finalization_aware (klass))
1448                         return BOEHM_GC_BIT_FINALIZER_AWARE;
1449         }
1450         return 0;
1451 }
1452
1453 /*
1454  * mono_gc_register_altstack:
1455  *
1456  *   Register the dimensions of the normal stack and altstack with the collector.
1457  * Currently, STACK/STACK_SIZE is only used when the thread is suspended while it is on an altstack.
1458  */
1459 void
1460 mono_gc_register_altstack (gpointer stack, gint32 stack_size, gpointer altstack, gint32 altstack_size)
1461 {
1462         GC_register_altstack (stack, stack_size, altstack, altstack_size);
1463 }
1464
1465 int
1466 mono_gc_get_los_limit (void)
1467 {
1468         return G_MAXINT;
1469 }
1470
1471 void
1472 mono_gc_set_string_length (MonoString *str, gint32 new_length)
1473 {
1474         mono_unichar2 *new_end = str->chars + new_length;
1475         
1476         /* zero the discarded string. This null-delimits the string and allows 
1477          * the space to be reclaimed by SGen. */
1478          
1479         memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
1480         str->length = new_length;
1481 }
1482
1483 gboolean
1484 mono_gc_user_markers_supported (void)
1485 {
1486         return FALSE;
1487 }
1488
1489 void *
1490 mono_gc_make_root_descr_user (MonoGCRootMarkFunc marker)
1491 {
1492         g_assert_not_reached ();
1493         return NULL;
1494 }
1495
1496 /* Toggleref support */
1497
1498 void
1499 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
1500 {
1501         if (GC_toggleref_add ((GC_PTR)object, (int)strong_ref) != GC_SUCCESS)
1502             g_error ("GC_toggleref_add failed\n");
1503 }
1504
1505 void
1506 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
1507 {
1508         GC_set_toggleref_func ((GC_ToggleRefStatus (*) (GC_PTR obj)) proccess_toggleref);
1509 }
1510
1511 /* Test support code */
1512
1513 static MonoToggleRefStatus
1514 test_toggleref_callback (MonoObject *obj)
1515 {
1516         static MonoClassField *mono_toggleref_test_field;
1517         MonoToggleRefStatus status = MONO_TOGGLE_REF_DROP;
1518
1519         if (!mono_toggleref_test_field) {
1520                 mono_toggleref_test_field = mono_class_get_field_from_name (mono_object_get_class (obj), "__test");
1521                 g_assert (mono_toggleref_test_field);
1522         }
1523
1524         mono_field_get_value (obj, mono_toggleref_test_field, &status);
1525         printf ("toggleref-cb obj %d\n", status);
1526         return status;
1527 }
1528
1529 static void
1530 register_test_toggleref_callback (void)
1531 {
1532         mono_gc_toggleref_register_callback (test_toggleref_callback);
1533 }
1534
1535 static gboolean
1536 is_finalization_aware (MonoObject *obj)
1537 {
1538         MonoVTable *vt = obj->vtable;
1539         return (vt->gc_bits & BOEHM_GC_BIT_FINALIZER_AWARE) == BOEHM_GC_BIT_FINALIZER_AWARE;
1540 }
1541
1542 static void
1543 fin_notifier (MonoObject *obj)
1544 {
1545         if (is_finalization_aware (obj))
1546                 fin_callbacks.object_queued_for_finalization (obj);
1547 }
1548
1549 void
1550 mono_gc_register_finalizer_callbacks (MonoGCFinalizerCallbacks *callbacks)
1551 {
1552         if (callbacks->version != MONO_GC_FINALIZER_EXTENSION_VERSION)
1553                 g_error ("Invalid finalizer callback version. Expected %d but got %d\n", MONO_GC_FINALIZER_EXTENSION_VERSION, callbacks->version);
1554
1555         fin_callbacks = *callbacks;
1556
1557         GC_set_await_finalize_proc ((void (*) (GC_PTR))fin_notifier);
1558 }
1559
1560 #define BITMAP_SIZE (sizeof (*((HandleData *)NULL)->bitmap) * CHAR_BIT)
1561
1562 static inline gboolean
1563 slot_occupied (HandleData *handles, guint slot) {
1564         return handles->bitmap [slot / BITMAP_SIZE] & (1 << (slot % BITMAP_SIZE));
1565 }
1566
1567 static inline void
1568 vacate_slot (HandleData *handles, guint slot) {
1569         handles->bitmap [slot / BITMAP_SIZE] &= ~(1 << (slot % BITMAP_SIZE));
1570 }
1571
1572 static inline void
1573 occupy_slot (HandleData *handles, guint slot) {
1574         handles->bitmap [slot / BITMAP_SIZE] |= 1 << (slot % BITMAP_SIZE);
1575 }
1576
1577 static int
1578 find_first_unset (guint32 bitmap)
1579 {
1580         int i;
1581         for (i = 0; i < 32; ++i) {
1582                 if (!(bitmap & (1 << i)))
1583                         return i;
1584         }
1585         return -1;
1586 }
1587
1588 static void
1589 handle_data_alloc_entries (HandleData *handles)
1590 {
1591         handles->size = 32;
1592         if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1593                 handles->entries = (void **)g_malloc0 (sizeof (*handles->entries) * handles->size);
1594                 handles->domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * handles->size);
1595         } else {
1596                 handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1597         }
1598         handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT);
1599 }
1600
1601 static gint
1602 handle_data_next_unset (HandleData *handles)
1603 {
1604         gint slot;
1605         for (slot = handles->slot_hint; slot < handles->size / BITMAP_SIZE; ++slot) {
1606                 if (handles->bitmap [slot] == 0xffffffff)
1607                         continue;
1608                 handles->slot_hint = slot;
1609                 return find_first_unset (handles->bitmap [slot]);
1610         }
1611         return -1;
1612 }
1613
1614 static gint
1615 handle_data_first_unset (HandleData *handles)
1616 {
1617         gint slot;
1618         for (slot = 0; slot < handles->slot_hint; ++slot) {
1619                 if (handles->bitmap [slot] == 0xffffffff)
1620                         continue;
1621                 handles->slot_hint = slot;
1622                 return find_first_unset (handles->bitmap [slot]);
1623         }
1624         return -1;
1625 }
1626
1627 /* Returns the index of the current slot in the bitmap. */
1628 static void
1629 handle_data_grow (HandleData *handles, gboolean track)
1630 {
1631         guint32 *new_bitmap;
1632         guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
1633
1634         /* resize and copy the bitmap */
1635         new_bitmap = (guint32 *)g_malloc0 (new_size / CHAR_BIT);
1636         memcpy (new_bitmap, handles->bitmap, handles->size / CHAR_BIT);
1637         g_free (handles->bitmap);
1638         handles->bitmap = new_bitmap;
1639
1640         /* resize and copy the entries */
1641         if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1642                 gpointer *entries;
1643                 guint16 *domain_ids;
1644                 gint i;
1645                 domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * new_size);
1646                 entries = (void **)g_malloc0 (sizeof (*handles->entries) * new_size);
1647                 memcpy (domain_ids, handles->domain_ids, sizeof (*handles->domain_ids) * handles->size);
1648                 for (i = 0; i < handles->size; ++i) {
1649                         MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
1650                         if (obj) {
1651                                 mono_gc_weak_link_add (&(entries [i]), obj, track);
1652                                 mono_gc_weak_link_remove (&(handles->entries [i]), track);
1653                         } else {
1654                                 g_assert (!handles->entries [i]);
1655                         }
1656                 }
1657                 g_free (handles->entries);
1658                 g_free (handles->domain_ids);
1659                 handles->entries = entries;
1660                 handles->domain_ids = domain_ids;
1661         } else {
1662                 gpointer *entries;
1663                 entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1664                 mono_gc_memmove_aligned (entries, handles->entries, sizeof (*handles->entries) * handles->size);
1665                 mono_gc_free_fixed (handles->entries);
1666                 handles->entries = entries;
1667         }
1668         handles->slot_hint = handles->size / BITMAP_SIZE;
1669         handles->size = new_size;
1670 }
1671
1672 static guint32
1673 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
1674 {
1675         gint slot, i;
1676         guint32 res;
1677         lock_handles (handles);
1678         if (!handles->size)
1679                 handle_data_alloc_entries (handles);
1680         i = handle_data_next_unset (handles);
1681         if (i == -1 && handles->slot_hint != 0)
1682                 i = handle_data_first_unset (handles);
1683         if (i == -1) {
1684                 handle_data_grow (handles, track);
1685                 i = 0;
1686         }
1687         slot = handles->slot_hint * BITMAP_SIZE + i;
1688         occupy_slot (handles, slot);
1689         handles->entries [slot] = NULL;
1690         if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1691                 /*FIXME, what to use when obj == null?*/
1692                 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1693                 if (obj)
1694                         mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
1695         } else {
1696                 handles->entries [slot] = obj;
1697         }
1698
1699 #ifndef DISABLE_PERFCOUNTERS
1700         mono_perfcounters->gc_num_handles++;
1701 #endif
1702         unlock_handles (handles);
1703         res = MONO_GC_HANDLE (slot, handles->type);
1704         mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
1705         return res;
1706 }
1707
1708 /**
1709  * mono_gchandle_new:
1710  * @obj: managed object to get a handle for
1711  * @pinned: whether the object should be pinned
1712  *
1713  * This returns a handle that wraps the object, this is used to keep a
1714  * reference to a managed object from the unmanaged world and preventing the
1715  * object from being disposed.
1716  * 
1717  * If @pinned is false the address of the object can not be obtained, if it is
1718  * true the address of the object can be obtained.  This will also pin the
1719  * object so it will not be possible by a moving garbage collector to move the
1720  * object. 
1721  * 
1722  * Returns: a handle that can be used to access the object from
1723  * unmanaged code.
1724  */
1725 guint32
1726 mono_gchandle_new (MonoObject *obj, gboolean pinned)
1727 {
1728         return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
1729 }
1730
1731 /**
1732  * mono_gchandle_new_weakref:
1733  * @obj: managed object to get a handle for
1734  * @track_resurrection: Determines how long to track the object, if this is set to TRUE, the object is tracked after finalization, if FALSE, the object is only tracked up until the point of finalization.
1735  *
1736  * This returns a weak handle that wraps the object, this is used to
1737  * keep a reference to a managed object from the unmanaged world.
1738  * Unlike the mono_gchandle_new the object can be reclaimed by the
1739  * garbage collector.  In this case the value of the GCHandle will be
1740  * set to zero.
1741  * 
1742  * If @track_resurrection is TRUE the object will be tracked through
1743  * finalization and if the object is resurrected during the execution
1744  * of the finalizer, then the returned weakref will continue to hold
1745  * a reference to the object.   If @track_resurrection is FALSE, then
1746  * the weak reference's target will become NULL as soon as the object
1747  * is passed on to the finalizer.
1748  * 
1749  * Returns: a handle that can be used to access the object from
1750  * unmanaged code.
1751  */
1752 guint32
1753 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
1754 {
1755         return alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
1756 }
1757
1758 /**
1759  * mono_gchandle_get_target:
1760  * @gchandle: a GCHandle's handle.
1761  *
1762  * The handle was previously created by calling `mono_gchandle_new` or
1763  * `mono_gchandle_new_weakref`.
1764  *
1765  * Returns: A pointer to the `MonoObject*` represented by the handle or
1766  * NULL for a collected object if using a weakref handle.
1767  */
1768 MonoObject*
1769 mono_gchandle_get_target (guint32 gchandle)
1770 {
1771         guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1772         guint type = MONO_GC_HANDLE_TYPE (gchandle);
1773         HandleData *handles = &gc_handles [type];
1774         MonoObject *obj = NULL;
1775         if (type >= HANDLE_TYPE_MAX)
1776                 return NULL;
1777
1778         lock_handles (handles);
1779         if (slot < handles->size && slot_occupied (handles, slot)) {
1780                 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1781                         obj = mono_gc_weak_link_get (&handles->entries [slot]);
1782                 } else {
1783                         obj = (MonoObject *)handles->entries [slot];
1784                 }
1785         } else {
1786                 /* print a warning? */
1787         }
1788         unlock_handles (handles);
1789         /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
1790         return obj;
1791 }
1792
1793 void
1794 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
1795 {
1796         guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1797         guint type = MONO_GC_HANDLE_TYPE (gchandle);
1798         HandleData *handles = &gc_handles [type];
1799         MonoObject *old_obj = NULL;
1800
1801         g_assert (type < HANDLE_TYPE_MAX);
1802         lock_handles (handles);
1803         if (slot < handles->size && slot_occupied (handles, slot)) {
1804                 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1805                         old_obj = (MonoObject *)handles->entries [slot];
1806                         if (handles->entries [slot])
1807                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1808                         if (obj)
1809                                 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
1810                         /*FIXME, what to use when obj == null?*/
1811                         handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1812                 } else {
1813                         handles->entries [slot] = obj;
1814                 }
1815         } else {
1816                 /* print a warning? */
1817         }
1818         /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
1819         unlock_handles (handles);
1820 }
1821
1822 gboolean
1823 mono_gc_is_null (void)
1824 {
1825         return FALSE;
1826 }
1827
1828 /**
1829  * mono_gchandle_is_in_domain:
1830  * @gchandle: a GCHandle's handle.
1831  * @domain: An application domain.
1832  *
1833  * Use this function to determine if the @gchandle points to an
1834  * object allocated in the specified @domain.
1835  *
1836  * Returns: TRUE if the object wrapped by the @gchandle belongs to the specific @domain.
1837  */
1838 gboolean
1839 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
1840 {
1841         guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1842         guint type = MONO_GC_HANDLE_TYPE (gchandle);
1843         HandleData *handles = &gc_handles [type];
1844         gboolean result = FALSE;
1845
1846         if (type >= HANDLE_TYPE_MAX)
1847                 return FALSE;
1848
1849         lock_handles (handles);
1850         if (slot < handles->size && slot_occupied (handles, slot)) {
1851                 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1852                         result = domain->domain_id == handles->domain_ids [slot];
1853                 } else {
1854                         MonoObject *obj;
1855                         obj = (MonoObject *)handles->entries [slot];
1856                         if (obj == NULL)
1857                                 result = TRUE;
1858                         else
1859                                 result = domain == mono_object_domain (obj);
1860                 }
1861         } else {
1862                 /* print a warning? */
1863         }
1864         unlock_handles (handles);
1865         return result;
1866 }
1867
1868 /**
1869  * mono_gchandle_free:
1870  * @gchandle: a GCHandle's handle.
1871  *
1872  * Frees the @gchandle handle.  If there are no outstanding
1873  * references, the garbage collector can reclaim the memory of the
1874  * object wrapped. 
1875  */
1876 void
1877 mono_gchandle_free (guint32 gchandle)
1878 {
1879         guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1880         guint type = MONO_GC_HANDLE_TYPE (gchandle);
1881         HandleData *handles = &gc_handles [type];
1882         if (type >= HANDLE_TYPE_MAX)
1883                 return;
1884
1885         lock_handles (handles);
1886         if (slot < handles->size && slot_occupied (handles, slot)) {
1887                 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1888                         if (handles->entries [slot])
1889                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1890                 } else {
1891                         handles->entries [slot] = NULL;
1892                 }
1893                 vacate_slot (handles, slot);
1894         } else {
1895                 /* print a warning? */
1896         }
1897 #ifndef DISABLE_PERFCOUNTERS
1898         mono_perfcounters->gc_num_handles--;
1899 #endif
1900         /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
1901         unlock_handles (handles);
1902         mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
1903 }
1904
1905 /**
1906  * mono_gchandle_free_domain:
1907  * @domain: domain that is unloading
1908  *
1909  * Function used internally to cleanup any GC handle for objects belonging
1910  * to the specified domain during appdomain unload.
1911  */
1912 void
1913 mono_gchandle_free_domain (MonoDomain *domain)
1914 {
1915         guint type;
1916
1917         for (type = HANDLE_TYPE_MIN; type < HANDLE_PINNED; ++type) {
1918                 guint slot;
1919                 HandleData *handles = &gc_handles [type];
1920                 lock_handles (handles);
1921                 for (slot = 0; slot < handles->size; ++slot) {
1922                         if (!slot_occupied (handles, slot))
1923                                 continue;
1924                         if (MONO_GC_HANDLE_TYPE_IS_WEAK (type)) {
1925                                 if (domain->domain_id == handles->domain_ids [slot]) {
1926                                         vacate_slot (handles, slot);
1927                                         if (handles->entries [slot])
1928                                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1929                                 }
1930                         } else {
1931                                 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
1932                                         vacate_slot (handles, slot);
1933                                         handles->entries [slot] = NULL;
1934                                 }
1935                         }
1936                 }
1937                 unlock_handles (handles);
1938         }
1939
1940 }
1941 #else
1942         #ifdef _MSC_VER
1943                 // Quiet Visual Studio linker warning, LNK4221, in cases when this source file intentional ends up empty.
1944                 void __mono_win32_boehm_gc_quiet_lnk4221(void) {}
1945         #endif
1946 #endif /* no Boehm GC */