Merge pull request #4169 from evincarofautumn/fix-xmm-scanning-mac-x86
[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/metadata/w32handle.h>
28 #include <mono/utils/atomic.h>
29 #include <mono/utils/mono-logger-internals.h>
30 #include <mono/utils/mono-memory-model.h>
31 #include <mono/utils/mono-time.h>
32 #include <mono/utils/mono-threads.h>
33 #include <mono/utils/dtrace.h>
34 #include <mono/utils/gc_wrapper.h>
35 #include <mono/utils/mono-os-mutex.h>
36 #include <mono/utils/mono-counters.h>
37 #include <mono/utils/mono-compiler.h>
38
39 #if HAVE_BOEHM_GC
40
41 #undef TRUE
42 #undef FALSE
43 #define THREAD_LOCAL_ALLOC 1
44 #include "private/pthread_support.h"
45
46 #if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
47 void *pthread_get_stackaddr_np(pthread_t);
48 #endif
49
50 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
51 /*Boehm max heap cannot be smaller than 16MB*/
52 #define MIN_BOEHM_MAX_HEAP_SIZE_IN_MB 16
53 #define MIN_BOEHM_MAX_HEAP_SIZE (MIN_BOEHM_MAX_HEAP_SIZE_IN_MB << 20)
54
55 static gboolean gc_initialized = FALSE;
56 static mono_mutex_t mono_gc_lock;
57
58 static void*
59 boehm_thread_register (MonoThreadInfo* info, void *baseptr);
60 static void
61 boehm_thread_unregister (MonoThreadInfo *p);
62 static void
63 boehm_thread_detach (MonoThreadInfo *p);
64 static void
65 register_test_toggleref_callback (void);
66
67 #define BOEHM_GC_BIT_FINALIZER_AWARE 1
68 static MonoGCFinalizerCallbacks fin_callbacks;
69
70 /* GC Handles */
71
72 static mono_mutex_t handle_section;
73 #define lock_handles(handles) mono_os_mutex_lock (&handle_section)
74 #define unlock_handles(handles) mono_os_mutex_unlock (&handle_section)
75
76 typedef struct {
77         guint32  *bitmap;
78         gpointer *entries;
79         guint32   size;
80         guint8    type;
81         guint     slot_hint : 24; /* starting slot for search in bitmap */
82         /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
83         /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
84         guint16  *domain_ids;
85 } HandleData;
86
87 #define EMPTY_HANDLE_DATA(type) {NULL, NULL, 0, (type), 0, NULL}
88
89 /* weak and weak-track arrays will be allocated in malloc memory 
90  */
91 static HandleData gc_handles [] = {
92         EMPTY_HANDLE_DATA (HANDLE_WEAK),
93         EMPTY_HANDLE_DATA (HANDLE_WEAK_TRACK),
94         EMPTY_HANDLE_DATA (HANDLE_NORMAL),
95         EMPTY_HANDLE_DATA (HANDLE_PINNED)
96 };
97
98 static void
99 mono_gc_warning (char *msg, GC_word arg)
100 {
101         mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_GC, msg, (unsigned long)arg);
102 }
103
104 static void on_gc_notification (GC_EventType event);
105 static void on_gc_heap_resize (size_t new_size);
106
107 void
108 mono_gc_base_init (void)
109 {
110         MonoThreadInfoCallbacks cb;
111         const char *env;
112         int dummy;
113
114         if (gc_initialized)
115                 return;
116
117         mono_counters_init ();
118
119 #ifndef HOST_WIN32
120         mono_w32handle_init ();
121 #endif
122
123         /*
124          * Handle the case when we are called from a thread different from the main thread,
125          * confusing libgc.
126          * FIXME: Move this to libgc where it belongs.
127          *
128          * we used to do this only when running on valgrind,
129          * but it happens also in other setups.
130          */
131 #if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK) && !defined(__native_client__)
132         {
133                 size_t size;
134                 void *sstart;
135                 pthread_attr_t attr;
136                 pthread_getattr_np (pthread_self (), &attr);
137                 pthread_attr_getstack (&attr, &sstart, &size);
138                 pthread_attr_destroy (&attr); 
139                 /*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/
140 #ifdef __ia64__
141                 /*
142                  * The calculation above doesn't seem to work on ia64, also we need to set
143                  * GC_register_stackbottom as well, but don't know how.
144                  */
145 #else
146                 /* apparently with some linuxthreads implementations sstart can be NULL,
147                  * fallback to the more imprecise method (bug# 78096).
148                  */
149                 if (sstart) {
150                         GC_stackbottom = (char*)sstart + size;
151                 } else {
152                         int dummy;
153                         gsize stack_bottom = (gsize)&dummy;
154                         stack_bottom += 4095;
155                         stack_bottom &= ~4095;
156                         GC_stackbottom = (char*)stack_bottom;
157                 }
158 #endif
159         }
160 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
161                 GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ());
162 #elif defined(__OpenBSD__)
163 #  include <pthread_np.h>
164         {
165                 stack_t ss;
166                 int rslt;
167
168                 rslt = pthread_stackseg_np(pthread_self(), &ss);
169                 g_assert (rslt == 0);
170
171                 GC_stackbottom = (char*)ss.ss_sp;
172         }
173 #elif defined(__native_client__)
174         /* Do nothing, GC_stackbottom is set correctly in libgc */
175 #else
176         {
177                 int dummy;
178                 gsize stack_bottom = (gsize)&dummy;
179                 stack_bottom += 4095;
180                 stack_bottom &= ~4095;
181                 /*g_print ("stackbottom is: %p\n", (char*)stack_bottom);*/
182                 GC_stackbottom = (char*)stack_bottom;
183         }
184 #endif
185
186 #if !defined(PLATFORM_ANDROID)
187         /* If GC_no_dls is set to true, GC_find_limit is not called. This causes a seg fault on Android. */
188         GC_no_dls = TRUE;
189 #endif
190         {
191                 if ((env = g_getenv ("MONO_GC_DEBUG"))) {
192                         char **opts = g_strsplit (env, ",", -1);
193                         for (char **ptr = opts; ptr && *ptr; ptr ++) {
194                                 char *opt = *ptr;
195                                 if (!strcmp (opt, "do-not-finalize")) {
196                                         mono_do_not_finalize = 1;
197                                 } else if (!strcmp (opt, "log-finalizers")) {
198                                         log_finalizers = 1;
199                                 }
200                         }
201                 }
202         }
203
204         GC_init ();
205
206         GC_set_warn_proc (mono_gc_warning);
207         GC_finalize_on_demand = 1;
208         GC_finalizer_notifier = mono_gc_finalize_notify;
209
210         GC_init_gcj_malloc (5, NULL);
211         GC_allow_register_threads ();
212
213         if ((env = g_getenv ("MONO_GC_PARAMS"))) {
214                 char **ptr, **opts = g_strsplit (env, ",", -1);
215                 for (ptr = opts; *ptr; ++ptr) {
216                         char *opt = *ptr;
217                         if (g_str_has_prefix (opt, "max-heap-size=")) {
218                                 size_t max_heap;
219
220                                 opt = strchr (opt, '=') + 1;
221                                 if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap)) {
222                                         if (max_heap < MIN_BOEHM_MAX_HEAP_SIZE) {
223                                                 fprintf (stderr, "max-heap-size must be at least %dMb.\n", MIN_BOEHM_MAX_HEAP_SIZE_IN_MB);
224                                                 exit (1);
225                                         }
226                                         GC_set_max_heap_size (max_heap);
227                                 } else {
228                                         fprintf (stderr, "max-heap-size must be an integer.\n");
229                                         exit (1);
230                                 }
231                                 continue;
232                         } else if (g_str_has_prefix (opt, "toggleref-test")) {
233                                 register_test_toggleref_callback ();
234                                 continue;
235                         } else {
236                                 /* Could be a parameter for sgen */
237                                 /*
238                                 fprintf (stderr, "MONO_GC_PARAMS must be a comma-delimited list of one or more of the following:\n");
239                                 fprintf (stderr, "  max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
240                                 exit (1);
241                                 */
242                         }
243                 }
244                 g_strfreev (opts);
245         }
246
247         memset (&cb, 0, sizeof (cb));
248         cb.thread_register = boehm_thread_register;
249         cb.thread_unregister = boehm_thread_unregister;
250         cb.thread_detach = boehm_thread_detach;
251         cb.mono_method_is_critical = (gboolean (*)(void *))mono_runtime_is_critical_method;
252
253         mono_threads_init (&cb, sizeof (MonoThreadInfo));
254         mono_os_mutex_init (&mono_gc_lock);
255         mono_os_mutex_init_recursive (&handle_section);
256
257         mono_thread_info_attach (&dummy);
258
259         GC_set_on_collection_event (on_gc_notification);
260         GC_on_heap_resize = on_gc_heap_resize;
261
262         gc_initialized = TRUE;
263 }
264
265 void
266 mono_gc_base_cleanup (void)
267 {
268         GC_finalizer_notifier = NULL;
269 }
270
271 /**
272  * mono_gc_collect:
273  * @generation: GC generation identifier
274  *
275  * Perform a garbage collection for the given generation, higher numbers
276  * mean usually older objects. Collecting a high-numbered generation
277  * implies collecting also the lower-numbered generations.
278  * The maximum value for @generation can be retrieved with a call to
279  * mono_gc_max_generation(), so this function is usually called as:
280  *
281  *      mono_gc_collect (mono_gc_max_generation ());
282  */
283 void
284 mono_gc_collect (int generation)
285 {
286 #ifndef DISABLE_PERFCOUNTERS
287         mono_perfcounters->gc_induced++;
288 #endif
289         GC_gcollect ();
290 }
291
292 /**
293  * mono_gc_max_generation:
294  *
295  * Get the maximum generation number used by the current garbage
296  * collector. The value will be 0 for the Boehm collector, 1 or more
297  * for the generational collectors.
298  *
299  * Returns: the maximum generation number.
300  */
301 int
302 mono_gc_max_generation (void)
303 {
304         return 0;
305 }
306
307 /**
308  * mono_gc_get_generation:
309  * @object: a managed object
310  *
311  * Get the garbage collector's generation that @object belongs to.
312  * Use this has a hint only.
313  *
314  * Returns: a garbage collector generation number
315  */
316 int
317 mono_gc_get_generation  (MonoObject *object)
318 {
319         return 0;
320 }
321
322 /**
323  * mono_gc_collection_count:
324  * @generation: a GC generation number
325  *
326  * Get how many times a garbage collection has been performed
327  * for the given @generation number.
328  *
329  * Returns: the number of garbage collections
330  */
331 int
332 mono_gc_collection_count (int generation)
333 {
334         return GC_gc_no;
335 }
336
337 /**
338  * mono_gc_add_memory_pressure:
339  * @value: amount of bytes
340  *
341  * Adjust the garbage collector's view of how many bytes of memory
342  * are indirectly referenced by managed objects (for example unmanaged
343  * memory holding image or other binary data).
344  * This is a hint only to the garbage collector algorithm.
345  * Note that negative amounts of @value will decrease the memory
346  * pressure.
347  */
348 void
349 mono_gc_add_memory_pressure (gint64 value)
350 {
351 }
352
353 /**
354  * mono_gc_get_used_size:
355  *
356  * Get the approximate amount of memory used by managed objects.
357  *
358  * Returns: the amount of memory used in bytes
359  */
360 int64_t
361 mono_gc_get_used_size (void)
362 {
363         return GC_get_heap_size () - GC_get_free_bytes ();
364 }
365
366 /**
367  * mono_gc_get_heap_size:
368  *
369  * Get the amount of memory used by the garbage collector.
370  *
371  * Returns: the size of the heap in bytes
372  */
373 int64_t
374 mono_gc_get_heap_size (void)
375 {
376         return GC_get_heap_size ();
377 }
378
379 gboolean
380 mono_gc_is_gc_thread (void)
381 {
382         return GC_thread_is_registered ();
383 }
384
385 gboolean
386 mono_gc_register_thread (void *baseptr)
387 {
388         return mono_thread_info_attach (baseptr) != NULL;
389 }
390
391 static void*
392 boehm_thread_register (MonoThreadInfo* info, void *baseptr)
393 {
394         struct GC_stack_base sb;
395         int res;
396
397         /* TODO: use GC_get_stack_base instead of baseptr. */
398         sb.mem_base = baseptr;
399         res = GC_register_my_thread (&sb);
400         if (res == GC_UNIMPLEMENTED)
401             return NULL; /* Cannot happen with GC v7+. */
402
403         info->handle_stack = mono_handle_stack_alloc ();
404
405         return info;
406 }
407
408 static void
409 boehm_thread_unregister (MonoThreadInfo *p)
410 {
411         MonoNativeThreadId tid;
412
413         tid = mono_thread_info_get_tid (p);
414
415         if (p->runtime_thread)
416                 mono_threads_add_joinable_thread ((gpointer)tid);
417 }
418
419 static void
420 boehm_thread_detach (MonoThreadInfo *p)
421 {
422         if (mono_thread_internal_current_is_attached ())
423                 mono_thread_detach_internal (mono_thread_internal_current ());
424 }
425
426 gboolean
427 mono_object_is_alive (MonoObject* o)
428 {
429         return GC_is_marked ((ptr_t)o);
430 }
431
432 int
433 mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
434 {
435         return 1;
436 }
437
438 static gint64 gc_start_time;
439
440 static void
441 on_gc_notification (GC_EventType event)
442 {
443         MonoGCEvent e = (MonoGCEvent)event;
444
445         switch (e) {
446         case MONO_GC_EVENT_PRE_STOP_WORLD:
447                 MONO_GC_WORLD_STOP_BEGIN ();
448                 break;
449
450         case MONO_GC_EVENT_POST_STOP_WORLD:
451                 MONO_GC_WORLD_STOP_END ();
452                 break;
453
454         case MONO_GC_EVENT_PRE_START_WORLD:
455                 MONO_GC_WORLD_RESTART_BEGIN (1);
456                 break;
457
458         case MONO_GC_EVENT_POST_START_WORLD:
459                 MONO_GC_WORLD_RESTART_END (1);
460                 break;
461
462         case MONO_GC_EVENT_START:
463                 MONO_GC_BEGIN (1);
464 #ifndef DISABLE_PERFCOUNTERS
465                 if (mono_perfcounters)
466                         mono_perfcounters->gc_collections0++;
467 #endif
468                 gc_stats.major_gc_count ++;
469                 gc_start_time = mono_100ns_ticks ();
470                 break;
471
472         case MONO_GC_EVENT_END:
473                 MONO_GC_END (1);
474 #if defined(ENABLE_DTRACE) && defined(__sun__)
475                 /* This works around a dtrace -G problem on Solaris.
476                    Limit its actual use to when the probe is enabled. */
477                 if (MONO_GC_END_ENABLED ())
478                         sleep(0);
479 #endif
480
481 #ifndef DISABLE_PERFCOUNTERS
482                 if (mono_perfcounters) {
483                         guint64 heap_size = GC_get_heap_size ();
484                         guint64 used_size = heap_size - GC_get_free_bytes ();
485                         mono_perfcounters->gc_total_bytes = used_size;
486                         mono_perfcounters->gc_committed_bytes = heap_size;
487                         mono_perfcounters->gc_reserved_bytes = heap_size;
488                         mono_perfcounters->gc_gen0size = heap_size;
489                 }
490 #endif
491                 gc_stats.major_gc_time += mono_100ns_ticks () - gc_start_time;
492                 mono_trace_message (MONO_TRACE_GC, "gc took %d usecs", (mono_100ns_ticks () - gc_start_time) / 10);
493                 break;
494         default:
495                 break;
496         }
497
498         mono_profiler_gc_event (e, 0);
499
500         switch (e) {
501         case MONO_GC_EVENT_PRE_STOP_WORLD:
502                 mono_thread_info_suspend_lock ();
503                 mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0);
504                 break;
505         case MONO_GC_EVENT_POST_START_WORLD:
506                 mono_thread_info_suspend_unlock ();
507                 mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0);
508                 break;
509         default:
510                 break;
511         }
512 }
513
514  
515 static void
516 on_gc_heap_resize (size_t new_size)
517 {
518         guint64 heap_size = GC_get_heap_size ();
519 #ifndef DISABLE_PERFCOUNTERS
520         if (mono_perfcounters) {
521                 mono_perfcounters->gc_committed_bytes = heap_size;
522                 mono_perfcounters->gc_reserved_bytes = heap_size;
523                 mono_perfcounters->gc_gen0size = heap_size;
524         }
525 #endif
526         mono_profiler_gc_heap_resize (new_size);
527 }
528
529 int
530 mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg)
531 {
532         /* for some strange reason, they want one extra byte on the end */
533         GC_add_roots (start, start + size + 1);
534
535         return TRUE;
536 }
537
538 int
539 mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg)
540 {
541         return mono_gc_register_root (start, size, descr, source, msg);
542 }
543
544 void
545 mono_gc_deregister_root (char* addr)
546 {
547 #ifndef HOST_WIN32
548         /* FIXME: libgc doesn't define this work win32 for some reason */
549         /* FIXME: No size info */
550         GC_remove_roots (addr, addr + sizeof (gpointer) + 1);
551 #endif
552 }
553
554 static void
555 mono_gc_weak_link_add (void **link_addr, MonoObject *obj, gboolean track)
556 {
557         /* libgc requires that we use HIDE_POINTER... */
558         *link_addr = (void*)HIDE_POINTER (obj);
559         if (track)
560                 GC_REGISTER_LONG_LINK (link_addr, obj);
561         else
562                 GC_GENERAL_REGISTER_DISAPPEARING_LINK (link_addr, obj);
563 }
564
565 static void
566 mono_gc_weak_link_remove (void **link_addr, gboolean track)
567 {
568         if (track)
569                 GC_unregister_long_link (link_addr);
570         else
571                 GC_unregister_disappearing_link (link_addr);
572         *link_addr = NULL;
573 }
574
575 static gpointer
576 reveal_link (gpointer link_addr)
577 {
578         void **link_a = (void **)link_addr;
579         return REVEAL_POINTER (*link_a);
580 }
581
582 static MonoObject *
583 mono_gc_weak_link_get (void **link_addr)
584 {
585         MonoObject *obj = (MonoObject *)GC_call_with_alloc_lock (reveal_link, link_addr);
586         if (obj == (MonoObject *) -1)
587                 return NULL;
588         return obj;
589 }
590
591 void*
592 mono_gc_make_descr_for_string (gsize *bitmap, int numbits)
593 {
594         return mono_gc_make_descr_from_bitmap (bitmap, numbits);
595 }
596
597 void*
598 mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
599 {
600         return mono_gc_make_descr_from_bitmap (bitmap, numbits);
601 }
602
603 void*
604 mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size)
605 {
606         /* libgc has no usable support for arrays... */
607         return GC_NO_DESCRIPTOR;
608 }
609
610 void*
611 mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits)
612 {
613         /* It seems there are issues when the bitmap doesn't fit: play it safe */
614         if (numbits >= 30)
615                 return GC_NO_DESCRIPTOR;
616         else
617                 return (gpointer)GC_make_descriptor ((GC_bitmap)bitmap, numbits);
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_getenv ("GC_DONT_GC"))
1317                 return TRUE;
1318         else
1319                 return FALSE;
1320 }
1321
1322 void
1323 mono_gc_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, unsigned bitmap)
1324 {
1325         g_assert_not_reached ();
1326 }
1327
1328
1329 guint8*
1330 mono_gc_get_card_table (int *shift_bits, gpointer *card_mask)
1331 {
1332         g_assert_not_reached ();
1333         return NULL;
1334 }
1335
1336 gboolean
1337 mono_gc_card_table_nursery_check (void)
1338 {
1339         g_assert_not_reached ();
1340         return TRUE;
1341 }
1342
1343 void*
1344 mono_gc_get_nursery (int *shift_bits, size_t *size)
1345 {
1346         return NULL;
1347 }
1348
1349 gboolean
1350 mono_gc_precise_stack_mark_enabled (void)
1351 {
1352         return FALSE;
1353 }
1354
1355 FILE *
1356 mono_gc_get_logfile (void)
1357 {
1358         return NULL;
1359 }
1360
1361 void
1362 mono_gc_params_set (const char* options)
1363 {
1364 }
1365
1366 void
1367 mono_gc_debug_set (const char* options)
1368 {
1369 }
1370
1371 void
1372 mono_gc_conservatively_scan_area (void *start, void *end)
1373 {
1374         g_assert_not_reached ();
1375 }
1376
1377 void *
1378 mono_gc_scan_object (void *obj, void *gc_data)
1379 {
1380         g_assert_not_reached ();
1381         return NULL;
1382 }
1383
1384 gsize*
1385 mono_gc_get_bitmap_for_descr (void *descr, int *numbits)
1386 {
1387         g_assert_not_reached ();
1388         return NULL;
1389 }
1390
1391 void
1392 mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks)
1393 {
1394 }
1395
1396 void
1397 mono_gc_set_stack_end (void *stack_end)
1398 {
1399 }
1400
1401 void mono_gc_set_skip_thread (gboolean value)
1402 {
1403 }
1404
1405 void
1406 mono_gc_register_for_finalization (MonoObject *obj, void *user_data)
1407 {
1408         guint offset = 0;
1409
1410 #ifndef GC_DEBUG
1411         /* This assertion is not valid when GC_DEBUG is defined */
1412         g_assert (GC_base (obj) == (char*)obj - offset);
1413 #endif
1414
1415         GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, (GC_finalization_proc)user_data, GUINT_TO_POINTER (offset), NULL, NULL);
1416 }
1417
1418 #ifndef HOST_WIN32
1419 int
1420 mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
1421 {
1422         /* it is being replaced by GC_pthread_create on some
1423          * platforms, see libgc/include/gc_pthread_redirects.h */
1424         return pthread_create (new_thread, attr, start_routine, arg);
1425 }
1426 #endif
1427
1428 #ifdef HOST_WIN32
1429 BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reserved)
1430 {
1431         return GC_DllMain (module_handle, reason, reserved);
1432 }
1433 #endif
1434
1435 guint
1436 mono_gc_get_vtable_bits (MonoClass *klass)
1437 {
1438         if (fin_callbacks.is_class_finalization_aware) {
1439                 if (fin_callbacks.is_class_finalization_aware (klass))
1440                         return BOEHM_GC_BIT_FINALIZER_AWARE;
1441         }
1442         return 0;
1443 }
1444
1445 /*
1446  * mono_gc_register_altstack:
1447  *
1448  *   Register the dimensions of the normal stack and altstack with the collector.
1449  * Currently, STACK/STACK_SIZE is only used when the thread is suspended while it is on an altstack.
1450  */
1451 void
1452 mono_gc_register_altstack (gpointer stack, gint32 stack_size, gpointer altstack, gint32 altstack_size)
1453 {
1454         GC_register_altstack (stack, stack_size, altstack, altstack_size);
1455 }
1456
1457 int
1458 mono_gc_get_los_limit (void)
1459 {
1460         return G_MAXINT;
1461 }
1462
1463 void
1464 mono_gc_set_string_length (MonoString *str, gint32 new_length)
1465 {
1466         mono_unichar2 *new_end = str->chars + new_length;
1467         
1468         /* zero the discarded string. This null-delimits the string and allows 
1469          * the space to be reclaimed by SGen. */
1470          
1471         memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
1472         str->length = new_length;
1473 }
1474
1475 gboolean
1476 mono_gc_user_markers_supported (void)
1477 {
1478         return FALSE;
1479 }
1480
1481 void *
1482 mono_gc_make_root_descr_user (MonoGCRootMarkFunc marker)
1483 {
1484         g_assert_not_reached ();
1485         return NULL;
1486 }
1487
1488 /* Toggleref support */
1489
1490 void
1491 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
1492 {
1493         if (GC_toggleref_add ((GC_PTR)object, (int)strong_ref) != GC_SUCCESS)
1494             g_error ("GC_toggleref_add failed\n");
1495 }
1496
1497 void
1498 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
1499 {
1500         GC_set_toggleref_func ((GC_ToggleRefStatus (*) (GC_PTR obj)) proccess_toggleref);
1501 }
1502
1503 /* Test support code */
1504
1505 static MonoToggleRefStatus
1506 test_toggleref_callback (MonoObject *obj)
1507 {
1508         static MonoClassField *mono_toggleref_test_field;
1509         MonoToggleRefStatus status = MONO_TOGGLE_REF_DROP;
1510
1511         if (!mono_toggleref_test_field) {
1512                 mono_toggleref_test_field = mono_class_get_field_from_name (mono_object_get_class (obj), "__test");
1513                 g_assert (mono_toggleref_test_field);
1514         }
1515
1516         mono_field_get_value (obj, mono_toggleref_test_field, &status);
1517         printf ("toggleref-cb obj %d\n", status);
1518         return status;
1519 }
1520
1521 static void
1522 register_test_toggleref_callback (void)
1523 {
1524         mono_gc_toggleref_register_callback (test_toggleref_callback);
1525 }
1526
1527 static gboolean
1528 is_finalization_aware (MonoObject *obj)
1529 {
1530         MonoVTable *vt = obj->vtable;
1531         return (vt->gc_bits & BOEHM_GC_BIT_FINALIZER_AWARE) == BOEHM_GC_BIT_FINALIZER_AWARE;
1532 }
1533
1534 static void
1535 fin_notifier (MonoObject *obj)
1536 {
1537         if (is_finalization_aware (obj))
1538                 fin_callbacks.object_queued_for_finalization (obj);
1539 }
1540
1541 void
1542 mono_gc_register_finalizer_callbacks (MonoGCFinalizerCallbacks *callbacks)
1543 {
1544         if (callbacks->version != MONO_GC_FINALIZER_EXTENSION_VERSION)
1545                 g_error ("Invalid finalizer callback version. Expected %d but got %d\n", MONO_GC_FINALIZER_EXTENSION_VERSION, callbacks->version);
1546
1547         fin_callbacks = *callbacks;
1548
1549         GC_set_await_finalize_proc ((void (*) (GC_PTR))fin_notifier);
1550 }
1551
1552 #define BITMAP_SIZE (sizeof (*((HandleData *)NULL)->bitmap) * CHAR_BIT)
1553
1554 static inline gboolean
1555 slot_occupied (HandleData *handles, guint slot) {
1556         return handles->bitmap [slot / BITMAP_SIZE] & (1 << (slot % BITMAP_SIZE));
1557 }
1558
1559 static inline void
1560 vacate_slot (HandleData *handles, guint slot) {
1561         handles->bitmap [slot / BITMAP_SIZE] &= ~(1 << (slot % BITMAP_SIZE));
1562 }
1563
1564 static inline void
1565 occupy_slot (HandleData *handles, guint slot) {
1566         handles->bitmap [slot / BITMAP_SIZE] |= 1 << (slot % BITMAP_SIZE);
1567 }
1568
1569 static int
1570 find_first_unset (guint32 bitmap)
1571 {
1572         int i;
1573         for (i = 0; i < 32; ++i) {
1574                 if (!(bitmap & (1 << i)))
1575                         return i;
1576         }
1577         return -1;
1578 }
1579
1580 static void
1581 handle_data_alloc_entries (HandleData *handles)
1582 {
1583         handles->size = 32;
1584         if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1585                 handles->entries = (void **)g_malloc0 (sizeof (*handles->entries) * handles->size);
1586                 handles->domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * handles->size);
1587         } else {
1588                 handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1589         }
1590         handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT);
1591 }
1592
1593 static gint
1594 handle_data_next_unset (HandleData *handles)
1595 {
1596         gint slot;
1597         for (slot = handles->slot_hint; slot < handles->size / BITMAP_SIZE; ++slot) {
1598                 if (handles->bitmap [slot] == 0xffffffff)
1599                         continue;
1600                 handles->slot_hint = slot;
1601                 return find_first_unset (handles->bitmap [slot]);
1602         }
1603         return -1;
1604 }
1605
1606 static gint
1607 handle_data_first_unset (HandleData *handles)
1608 {
1609         gint slot;
1610         for (slot = 0; slot < handles->slot_hint; ++slot) {
1611                 if (handles->bitmap [slot] == 0xffffffff)
1612                         continue;
1613                 handles->slot_hint = slot;
1614                 return find_first_unset (handles->bitmap [slot]);
1615         }
1616         return -1;
1617 }
1618
1619 /* Returns the index of the current slot in the bitmap. */
1620 static void
1621 handle_data_grow (HandleData *handles, gboolean track)
1622 {
1623         guint32 *new_bitmap;
1624         guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
1625
1626         /* resize and copy the bitmap */
1627         new_bitmap = (guint32 *)g_malloc0 (new_size / CHAR_BIT);
1628         memcpy (new_bitmap, handles->bitmap, handles->size / CHAR_BIT);
1629         g_free (handles->bitmap);
1630         handles->bitmap = new_bitmap;
1631
1632         /* resize and copy the entries */
1633         if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1634                 gpointer *entries;
1635                 guint16 *domain_ids;
1636                 gint i;
1637                 domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * new_size);
1638                 entries = (void **)g_malloc0 (sizeof (*handles->entries) * new_size);
1639                 memcpy (domain_ids, handles->domain_ids, sizeof (*handles->domain_ids) * handles->size);
1640                 for (i = 0; i < handles->size; ++i) {
1641                         MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
1642                         if (obj) {
1643                                 mono_gc_weak_link_add (&(entries [i]), obj, track);
1644                                 mono_gc_weak_link_remove (&(handles->entries [i]), track);
1645                         } else {
1646                                 g_assert (!handles->entries [i]);
1647                         }
1648                 }
1649                 g_free (handles->entries);
1650                 g_free (handles->domain_ids);
1651                 handles->entries = entries;
1652                 handles->domain_ids = domain_ids;
1653         } else {
1654                 gpointer *entries;
1655                 entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1656                 mono_gc_memmove_aligned (entries, handles->entries, sizeof (*handles->entries) * handles->size);
1657                 mono_gc_free_fixed (handles->entries);
1658                 handles->entries = entries;
1659         }
1660         handles->slot_hint = handles->size / BITMAP_SIZE;
1661         handles->size = new_size;
1662 }
1663
1664 static guint32
1665 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
1666 {
1667         gint slot, i;
1668         guint32 res;
1669         lock_handles (handles);
1670         if (!handles->size)
1671                 handle_data_alloc_entries (handles);
1672         i = handle_data_next_unset (handles);
1673         if (i == -1 && handles->slot_hint != 0)
1674                 i = handle_data_first_unset (handles);
1675         if (i == -1) {
1676                 handle_data_grow (handles, track);
1677                 i = 0;
1678         }
1679         slot = handles->slot_hint * BITMAP_SIZE + i;
1680         occupy_slot (handles, slot);
1681         handles->entries [slot] = NULL;
1682         if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1683                 /*FIXME, what to use when obj == null?*/
1684                 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1685                 if (obj)
1686                         mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
1687         } else {
1688                 handles->entries [slot] = obj;
1689         }
1690
1691 #ifndef DISABLE_PERFCOUNTERS
1692         mono_perfcounters->gc_num_handles++;
1693 #endif
1694         unlock_handles (handles);
1695         res = MONO_GC_HANDLE (slot, handles->type);
1696         mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
1697         return res;
1698 }
1699
1700 /**
1701  * mono_gchandle_new:
1702  * @obj: managed object to get a handle for
1703  * @pinned: whether the object should be pinned
1704  *
1705  * This returns a handle that wraps the object, this is used to keep a
1706  * reference to a managed object from the unmanaged world and preventing the
1707  * object from being disposed.
1708  * 
1709  * If @pinned is false the address of the object can not be obtained, if it is
1710  * true the address of the object can be obtained.  This will also pin the
1711  * object so it will not be possible by a moving garbage collector to move the
1712  * object. 
1713  * 
1714  * Returns: a handle that can be used to access the object from
1715  * unmanaged code.
1716  */
1717 guint32
1718 mono_gchandle_new (MonoObject *obj, gboolean pinned)
1719 {
1720         return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
1721 }
1722
1723 /**
1724  * mono_gchandle_new_weakref:
1725  * @obj: managed object to get a handle for
1726  * @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.
1727  *
1728  * This returns a weak handle that wraps the object, this is used to
1729  * keep a reference to a managed object from the unmanaged world.
1730  * Unlike the mono_gchandle_new the object can be reclaimed by the
1731  * garbage collector.  In this case the value of the GCHandle will be
1732  * set to zero.
1733  * 
1734  * If @track_resurrection is TRUE the object will be tracked through
1735  * finalization and if the object is resurrected during the execution
1736  * of the finalizer, then the returned weakref will continue to hold
1737  * a reference to the object.   If @track_resurrection is FALSE, then
1738  * the weak reference's target will become NULL as soon as the object
1739  * is passed on to the finalizer.
1740  * 
1741  * Returns: a handle that can be used to access the object from
1742  * unmanaged code.
1743  */
1744 guint32
1745 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
1746 {
1747         return alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
1748 }
1749
1750 /**
1751  * mono_gchandle_get_target:
1752  * @gchandle: a GCHandle's handle.
1753  *
1754  * The handle was previously created by calling `mono_gchandle_new` or
1755  * `mono_gchandle_new_weakref`.
1756  *
1757  * Returns: A pointer to the `MonoObject*` represented by the handle or
1758  * NULL for a collected object if using a weakref handle.
1759  */
1760 MonoObject*
1761 mono_gchandle_get_target (guint32 gchandle)
1762 {
1763         guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1764         guint type = MONO_GC_HANDLE_TYPE (gchandle);
1765         HandleData *handles = &gc_handles [type];
1766         MonoObject *obj = NULL;
1767         if (type >= HANDLE_TYPE_MAX)
1768                 return NULL;
1769
1770         lock_handles (handles);
1771         if (slot < handles->size && slot_occupied (handles, slot)) {
1772                 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1773                         obj = mono_gc_weak_link_get (&handles->entries [slot]);
1774                 } else {
1775                         obj = (MonoObject *)handles->entries [slot];
1776                 }
1777         } else {
1778                 /* print a warning? */
1779         }
1780         unlock_handles (handles);
1781         /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
1782         return obj;
1783 }
1784
1785 void
1786 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
1787 {
1788         guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1789         guint type = MONO_GC_HANDLE_TYPE (gchandle);
1790         HandleData *handles = &gc_handles [type];
1791         MonoObject *old_obj = NULL;
1792
1793         g_assert (type < HANDLE_TYPE_MAX);
1794         lock_handles (handles);
1795         if (slot < handles->size && slot_occupied (handles, slot)) {
1796                 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1797                         old_obj = (MonoObject *)handles->entries [slot];
1798                         if (handles->entries [slot])
1799                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1800                         if (obj)
1801                                 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
1802                         /*FIXME, what to use when obj == null?*/
1803                         handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1804                 } else {
1805                         handles->entries [slot] = obj;
1806                 }
1807         } else {
1808                 /* print a warning? */
1809         }
1810         /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
1811         unlock_handles (handles);
1812 }
1813
1814 gboolean
1815 mono_gc_is_null (void)
1816 {
1817         return FALSE;
1818 }
1819
1820 /**
1821  * mono_gchandle_is_in_domain:
1822  * @gchandle: a GCHandle's handle.
1823  * @domain: An application domain.
1824  *
1825  * Use this function to determine if the @gchandle points to an
1826  * object allocated in the specified @domain.
1827  *
1828  * Returns: TRUE if the object wrapped by the @gchandle belongs to the specific @domain.
1829  */
1830 gboolean
1831 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
1832 {
1833         guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1834         guint type = MONO_GC_HANDLE_TYPE (gchandle);
1835         HandleData *handles = &gc_handles [type];
1836         gboolean result = FALSE;
1837
1838         if (type >= HANDLE_TYPE_MAX)
1839                 return FALSE;
1840
1841         lock_handles (handles);
1842         if (slot < handles->size && slot_occupied (handles, slot)) {
1843                 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1844                         result = domain->domain_id == handles->domain_ids [slot];
1845                 } else {
1846                         MonoObject *obj;
1847                         obj = (MonoObject *)handles->entries [slot];
1848                         if (obj == NULL)
1849                                 result = TRUE;
1850                         else
1851                                 result = domain == mono_object_domain (obj);
1852                 }
1853         } else {
1854                 /* print a warning? */
1855         }
1856         unlock_handles (handles);
1857         return result;
1858 }
1859
1860 /**
1861  * mono_gchandle_free:
1862  * @gchandle: a GCHandle's handle.
1863  *
1864  * Frees the @gchandle handle.  If there are no outstanding
1865  * references, the garbage collector can reclaim the memory of the
1866  * object wrapped. 
1867  */
1868 void
1869 mono_gchandle_free (guint32 gchandle)
1870 {
1871         guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1872         guint type = MONO_GC_HANDLE_TYPE (gchandle);
1873         HandleData *handles = &gc_handles [type];
1874         if (type >= HANDLE_TYPE_MAX)
1875                 return;
1876
1877         lock_handles (handles);
1878         if (slot < handles->size && slot_occupied (handles, slot)) {
1879                 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1880                         if (handles->entries [slot])
1881                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1882                 } else {
1883                         handles->entries [slot] = NULL;
1884                 }
1885                 vacate_slot (handles, slot);
1886         } else {
1887                 /* print a warning? */
1888         }
1889 #ifndef DISABLE_PERFCOUNTERS
1890         mono_perfcounters->gc_num_handles--;
1891 #endif
1892         /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
1893         unlock_handles (handles);
1894         mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
1895 }
1896
1897 /**
1898  * mono_gchandle_free_domain:
1899  * @domain: domain that is unloading
1900  *
1901  * Function used internally to cleanup any GC handle for objects belonging
1902  * to the specified domain during appdomain unload.
1903  */
1904 void
1905 mono_gchandle_free_domain (MonoDomain *domain)
1906 {
1907         guint type;
1908
1909         for (type = HANDLE_TYPE_MIN; type < HANDLE_PINNED; ++type) {
1910                 guint slot;
1911                 HandleData *handles = &gc_handles [type];
1912                 lock_handles (handles);
1913                 for (slot = 0; slot < handles->size; ++slot) {
1914                         if (!slot_occupied (handles, slot))
1915                                 continue;
1916                         if (MONO_GC_HANDLE_TYPE_IS_WEAK (type)) {
1917                                 if (domain->domain_id == handles->domain_ids [slot]) {
1918                                         vacate_slot (handles, slot);
1919                                         if (handles->entries [slot])
1920                                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1921                                 }
1922                         } else {
1923                                 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
1924                                         vacate_slot (handles, slot);
1925                                         handles->entries [slot] = NULL;
1926                                 }
1927                         }
1928                 }
1929                 unlock_handles (handles);
1930         }
1931
1932 }
1933 #else
1934
1935 MONO_EMPTY_SOURCE_FILE (boehm_gc);
1936 #endif /* no Boehm GC */