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