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