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