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