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