3 * GC implementation using either the installed or included Boehm GC.
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.
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>
44 #define THREAD_LOCAL_ALLOC 1
45 #include "private/pthread_support.h"
47 #if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
48 void *pthread_get_stackaddr_np(pthread_t);
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)
56 static gboolean gc_initialized = FALSE;
57 static mono_mutex_t mono_gc_lock;
60 boehm_thread_attach (MonoThreadInfo* info);
62 boehm_thread_detach_with_lock (MonoThreadInfo *p);
64 boehm_thread_detach (MonoThreadInfo *p);
66 register_test_toggleref_callback (void);
68 #define BOEHM_GC_BIT_FINALIZER_AWARE 1
69 static MonoGCFinalizerCallbacks fin_callbacks;
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)
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 */
88 #define EMPTY_HANDLE_DATA(type) {NULL, NULL, 0, (type), 0, NULL}
90 /* weak and weak-track arrays will be allocated in malloc memory
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)
100 mono_gc_warning (char *msg, GC_word arg)
102 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_GC, msg, (unsigned long)arg);
105 static void on_gc_notification (GC_EventType event);
106 static void on_gc_heap_resize (size_t new_size);
109 mono_gc_base_init (void)
111 MonoThreadInfoCallbacks cb;
117 mono_counters_init ();
120 mono_w32handle_init ();
124 * Handle the case when we are called from a thread different from the main thread,
126 * FIXME: Move this to libgc where it belongs.
128 * we used to do this only when running on valgrind,
129 * but it happens also in other setups.
131 #if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
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).
144 GC_stackbottom = (char*)sstart + size;
147 gsize stack_bottom = (gsize)&dummy;
148 stack_bottom += 4095;
149 stack_bottom &= ~4095;
150 GC_stackbottom = (char*)stack_bottom;
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>
161 rslt = pthread_stackseg_np(pthread_self(), &ss);
162 g_assert (rslt == 0);
164 GC_stackbottom = (char*)ss.ss_sp;
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;
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. */
182 if ((env = g_getenv ("MONO_GC_DEBUG"))) {
183 char **opts = g_strsplit (env, ",", -1);
184 for (char **ptr = opts; ptr && *ptr; ptr ++) {
186 if (!strcmp (opt, "do-not-finalize")) {
187 mono_do_not_finalize = 1;
188 } else if (!strcmp (opt, "log-finalizers")) {
198 GC_set_warn_proc (mono_gc_warning);
199 GC_finalize_on_demand = 1;
200 GC_finalizer_notifier = mono_gc_finalize_notify;
202 GC_init_gcj_malloc (5, NULL);
203 GC_allow_register_threads ();
205 if ((env = g_getenv ("MONO_GC_PARAMS"))) {
206 char **ptr, **opts = g_strsplit (env, ",", -1);
207 for (ptr = opts; *ptr; ++ptr) {
209 if (g_str_has_prefix (opt, "max-heap-size=")) {
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);
218 GC_set_max_heap_size (max_heap);
220 fprintf (stderr, "max-heap-size must be an integer.\n");
224 } else if (g_str_has_prefix (opt, "toggleref-test")) {
225 register_test_toggleref_callback ();
228 /* Could be a parameter for sgen */
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");
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;
246 mono_threads_init (&cb, sizeof (MonoThreadInfo));
247 mono_os_mutex_init (&mono_gc_lock);
248 mono_os_mutex_init_recursive (&handle_section);
250 mono_thread_info_attach ();
252 GC_set_on_collection_event (on_gc_notification);
253 GC_on_heap_resize = on_gc_heap_resize;
255 gc_initialized = TRUE;
259 mono_gc_base_cleanup (void)
261 GC_finalizer_notifier = NULL;
266 * \param generation GC generation identifier
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:
274 * <code>mono_gc_collect (mono_gc_max_generation ());</code>
277 mono_gc_collect (int generation)
279 #ifndef DISABLE_PERFCOUNTERS
280 mono_perfcounters->gc_induced++;
286 * mono_gc_max_generation:
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.
292 * Returns: the maximum generation number.
295 mono_gc_max_generation (void)
301 * mono_gc_get_generation:
302 * \param object a managed object
304 * Get the garbage collector's generation that \p object belongs to.
305 * Use this has a hint only.
307 * \returns a garbage collector generation number
310 mono_gc_get_generation (MonoObject *object)
316 * mono_gc_collection_count:
317 * \param generation a GC generation number
319 * Get how many times a garbage collection has been performed
320 * for the given \p generation number.
322 * \returns the number of garbage collections
325 mono_gc_collection_count (int generation)
331 * mono_gc_add_memory_pressure:
332 * \param value amount of bytes
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
342 mono_gc_add_memory_pressure (gint64 value)
347 * mono_gc_get_used_size:
349 * Get the approximate amount of memory used by managed objects.
351 * Returns: the amount of memory used in bytes
354 mono_gc_get_used_size (void)
356 return GC_get_heap_size () - GC_get_free_bytes ();
360 * mono_gc_get_heap_size:
362 * Get the amount of memory used by the garbage collector.
364 * Returns: the size of the heap in bytes
367 mono_gc_get_heap_size (void)
369 return GC_get_heap_size ();
373 mono_gc_is_gc_thread (void)
375 return GC_thread_is_registered ();
379 boehm_thread_attach (MonoThreadInfo* info)
381 struct GC_stack_base sb;
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+. */
390 info->handle_stack = mono_handle_stack_alloc ();
396 boehm_thread_detach_with_lock (MonoThreadInfo *p)
398 MonoNativeThreadId tid;
400 tid = mono_thread_info_get_tid (p);
402 if (p->runtime_thread)
403 mono_threads_add_joinable_thread ((gpointer)tid);
405 mono_handle_stack_free (p->handle_stack);
409 boehm_thread_detach (MonoThreadInfo *p)
411 if (mono_thread_internal_current_is_attached ())
412 mono_thread_detach_internal (mono_thread_internal_current ());
416 mono_object_is_alive (MonoObject* o)
418 return GC_is_marked ((ptr_t)o);
422 mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
427 static gint64 gc_start_time;
430 on_gc_notification (GC_EventType event)
432 MonoGCEvent e = (MonoGCEvent)event;
435 case MONO_GC_EVENT_PRE_STOP_WORLD:
436 MONO_GC_WORLD_STOP_BEGIN ();
439 case MONO_GC_EVENT_POST_STOP_WORLD:
440 MONO_GC_WORLD_STOP_END ();
443 case MONO_GC_EVENT_PRE_START_WORLD:
444 MONO_GC_WORLD_RESTART_BEGIN (1);
447 case MONO_GC_EVENT_POST_START_WORLD:
448 MONO_GC_WORLD_RESTART_END (1);
451 case MONO_GC_EVENT_START:
453 #ifndef DISABLE_PERFCOUNTERS
454 if (mono_perfcounters)
455 mono_perfcounters->gc_collections0++;
457 gc_stats.major_gc_count ++;
458 gc_start_time = mono_100ns_ticks ();
461 case MONO_GC_EVENT_END:
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 ())
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;
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);
487 mono_profiler_gc_event (e, 0);
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);
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);
505 on_gc_heap_resize (size_t new_size)
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;
515 mono_profiler_gc_heap_resize (new_size);
519 mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg)
521 /* for some strange reason, they want one extra byte on the end */
522 GC_add_roots (start, start + size + 1);
528 mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg)
530 return mono_gc_register_root (start, size, descr, source, msg);
534 mono_gc_deregister_root (char* addr)
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);
544 mono_gc_weak_link_add (void **link_addr, MonoObject *obj, gboolean track)
546 /* libgc requires that we use HIDE_POINTER... */
547 *link_addr = (void*)HIDE_POINTER (obj);
549 GC_REGISTER_LONG_LINK (link_addr, obj);
551 GC_GENERAL_REGISTER_DISAPPEARING_LINK (link_addr, obj);
555 mono_gc_weak_link_remove (void **link_addr, gboolean track)
558 GC_unregister_long_link (link_addr);
560 GC_unregister_disappearing_link (link_addr);
565 reveal_link (gpointer link_addr)
567 void **link_a = (void **)link_addr;
568 return REVEAL_POINTER (*link_a);
572 mono_gc_weak_link_get (void **link_addr)
574 MonoObject *obj = (MonoObject *)GC_call_with_alloc_lock (reveal_link, link_addr);
575 if (obj == (MonoObject *) -1)
581 mono_gc_make_descr_for_string (gsize *bitmap, int numbits)
583 return mono_gc_make_descr_from_bitmap (bitmap, numbits);
587 mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
589 return mono_gc_make_descr_from_bitmap (bitmap, numbits);
593 mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size)
595 /* libgc has no usable support for arrays... */
596 return GC_NO_DESCRIPTOR;
600 mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits)
602 /* It seems there are issues when the bitmap doesn't fit: play it safe */
604 return GC_NO_DESCRIPTOR;
606 return (gpointer)GC_make_descriptor ((GC_bitmap)bitmap, numbits);
610 mono_gc_make_vector_descr (void)
616 mono_gc_make_root_descr_all_refs (int numbits)
622 mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, const char *msg)
624 return GC_MALLOC_UNCOLLECTABLE (size);
628 mono_gc_free_fixed (void* addr)
634 mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
638 if (!vtable->klass->has_references) {
639 obj = (MonoObject *)GC_MALLOC_ATOMIC (size);
640 if (G_UNLIKELY (!obj))
643 obj->vtable = vtable;
644 obj->synchronisation = NULL;
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))
652 obj = (MonoObject *)GC_MALLOC (size);
653 if (G_UNLIKELY (!obj))
656 obj->vtable = vtable;
659 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
660 mono_profiler_allocation (obj);
666 mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
670 if (!vtable->klass->has_references) {
671 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
672 if (G_UNLIKELY (!obj))
675 obj->obj.vtable = vtable;
676 obj->obj.synchronisation = NULL;
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))
684 obj = (MonoArray *)GC_MALLOC (size);
685 if (G_UNLIKELY (!obj))
688 obj->obj.vtable = vtable;
691 obj->max_length = max_length;
693 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
694 mono_profiler_allocation (&obj->obj);
700 mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uintptr_t bounds_size)
704 if (!vtable->klass->has_references) {
705 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
706 if (G_UNLIKELY (!obj))
709 obj->obj.vtable = vtable;
710 obj->obj.synchronisation = NULL;
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))
718 obj = (MonoArray *)GC_MALLOC (size);
719 if (G_UNLIKELY (!obj))
722 obj->obj.vtable = vtable;
725 obj->max_length = max_length;
728 obj->bounds = (MonoArrayBounds *) ((char *) obj + size - bounds_size);
730 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
731 mono_profiler_allocation (&obj->obj);
737 mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
739 MonoString *obj = (MonoString *)GC_MALLOC_ATOMIC (size);
740 if (G_UNLIKELY (!obj))
743 obj->object.vtable = vtable;
744 obj->object.synchronisation = NULL;
746 obj->chars [len] = 0;
748 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
749 mono_profiler_allocation (&obj->object);
755 mono_gc_alloc_mature (MonoVTable *vtable, size_t size)
757 return mono_gc_alloc_obj (vtable, size);
761 mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size)
763 return mono_gc_alloc_obj (vtable, size);
767 mono_gc_invoke_finalizers (void)
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.
774 if (GC_should_invoke_finalizers ())
775 return GC_invoke_finalizers ();
780 mono_gc_pending_finalizers (void)
782 return GC_should_invoke_finalizers ();
786 mono_gc_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* value)
788 *(void**)field_ptr = value;
792 mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* value)
794 *(void**)slot_ptr = value;
798 mono_gc_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
800 mono_gc_memmove_aligned (dest_ptr, src_ptr, count * sizeof (gpointer));
804 mono_gc_wbarrier_generic_store (gpointer ptr, MonoObject* value)
806 *(void**)ptr = value;
810 mono_gc_wbarrier_generic_store_atomic (gpointer ptr, MonoObject *value)
812 InterlockedWritePointer ((volatile gpointer *)ptr, value);
816 mono_gc_wbarrier_generic_nostore (gpointer ptr)
821 mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass)
823 mono_gc_memmove_atomic (dest, src, count * mono_class_value_size (klass, NULL));
827 mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
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));
835 mono_gc_clear_domain (MonoDomain *domain)
840 mono_gc_suspend_finalizers (void)
845 mono_gc_get_suspend_signal (void)
847 return GC_get_suspend_signal ();
851 mono_gc_get_restart_signal (void)
853 return GC_get_thr_restart_signal ();
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"
864 while (!(v & (1 << i)))
871 ATYPE_FREEPTR_FOR_BOX,
879 create_allocator (int atype, int tls_key, gboolean slowpath)
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;
886 MonoMethodSignature *csig;
887 const char *name = NULL;
890 g_assert_not_reached ();
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";
903 g_assert_not_reached ();
906 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
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;
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;
918 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ALLOC);
921 goto always_slowpath;
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);
937 mono_mb_emit_ldarg (mb, 1);
938 mono_mb_emit_stloc (mb, bytes_var);
941 /* this is needed for strings/arrays only as the other big types are never allocated with this method */
942 if (atype == ATYPE_STRING) {
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);
954 /* int index = INDEX_FROM_BYTES(bytes); */
955 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
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);
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,
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,
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,
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);
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);
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);
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);
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);
1013 if (atype == ATYPE_FREEPTR) {
1014 int start_var, end_var, start_loop;
1015 /* end = my_entry + bytes; start = my_entry + sizeof (gpointer);
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);
1030 * } while (start < end);
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);
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);
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);
1072 /* return my_entry; */
1073 mono_mb_emit_ldloc (mb, my_entry_var);
1074 mono_mb_emit_byte (mb, MONO_CEE_RET);
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);
1082 /* the slow path: we just call back into the runtime */
1084 if (atype == ATYPE_STRING) {
1085 mono_mb_emit_ldarg (mb, 1);
1086 mono_mb_emit_icall (mb, ves_icall_string_alloc);
1088 mono_mb_emit_ldarg (mb, 0);
1089 mono_mb_emit_icall (mb, ves_icall_object_new_specific);
1092 mono_mb_emit_byte (mb, MONO_CEE_RET);
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;
1099 res = mono_mb_create (mb, csig, 8, info);
1105 static MonoMethod* alloc_method_cache [ATYPE_NUM];
1106 static MonoMethod* slowpath_alloc_method_cache [ATYPE_NUM];
1109 mono_gc_is_critical_method (MonoMethod *method)
1113 for (i = 0; i < ATYPE_NUM; ++i)
1114 if (method == alloc_method_cache [i] || method == slowpath_alloc_method_cache [i])
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,
1127 * The thread local alloc logic is taken from libgc/pthread_support.c.
1131 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1136 * Tls implementation changed, we jump to tls native getters/setters.
1137 * Is boehm managed allocator ok with this ? Do we even care ?
1141 if (!SMALL_ENOUGH (klass->instance_size))
1143 if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass))
1145 if (mono_profiler_get_events () & (MONO_PROFILE_ALLOCATIONS | MONO_PROFILE_STATISTICAL))
1149 if (mono_class_is_open_constructed_type (&klass->byval_arg))
1151 if (klass->byval_arg.type == MONO_TYPE_STRING) {
1152 atype = ATYPE_STRING;
1153 } else if (!known_instance_size) {
1155 } else if (!klass->has_references) {
1157 atype = ATYPE_FREEPTR_FOR_BOX;
1159 atype = ATYPE_FREEPTR;
1163 * disabled because we currently do a runtime choice anyway, to
1164 * deal with multiple appdomains.
1165 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1168 atype = ATYPE_NORMAL;
1171 return mono_gc_get_managed_allocator_by_type (atype, MANAGED_ALLOCATOR_REGULAR);
1175 mono_gc_get_managed_array_allocator (MonoClass *klass)
1181 * mono_gc_get_managed_allocator_by_type:
1183 * Return a managed allocator method corresponding to allocator type ATYPE.
1186 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1189 gboolean slowpath = variant != MANAGED_ALLOCATOR_REGULAR;
1190 MonoMethod **cache = slowpath ? slowpath_alloc_method_cache : alloc_method_cache;
1194 res = cache [atype];
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];
1204 mono_memory_barrier ();
1205 cache [atype] = res;
1207 mono_os_mutex_unlock (&mono_gc_lock);
1212 mono_gc_get_managed_allocator_types (void)
1218 mono_gc_get_write_barrier (void)
1220 g_assert_not_reached ();
1227 mono_gc_is_critical_method (MonoMethod *method)
1233 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1239 mono_gc_get_managed_array_allocator (MonoClass *klass)
1245 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1251 mono_gc_get_managed_allocator_types (void)
1257 mono_gc_get_write_barrier (void)
1259 g_assert_not_reached ();
1266 mono_gc_get_specific_write_barrier (gboolean is_concurrent)
1268 g_assert_not_reached ();
1273 mono_gc_get_aligned_size_for_allocator (int size)
1279 mono_gc_get_gc_name (void)
1285 mono_gc_invoke_with_gc_lock (MonoGCLockedCallbackFunc func, void *data)
1287 return GC_call_with_alloc_lock (func, data);
1291 mono_gc_get_description (void)
1293 return g_strdup (DEFAULT_GC_NAME);
1297 mono_gc_set_desktop_mode (void)
1303 mono_gc_is_moving (void)
1309 mono_gc_is_disabled (void)
1311 if (GC_dont_gc || g_hasenv ("GC_DONT_GC"))
1318 mono_gc_wbarrier_range_copy (gpointer _dest, gpointer _src, int size)
1320 g_assert_not_reached ();
1324 mono_gc_get_range_copy_func (void)
1326 return &mono_gc_wbarrier_range_copy;
1330 mono_gc_get_card_table (int *shift_bits, gpointer *card_mask)
1332 g_assert_not_reached ();
1337 mono_gc_card_table_nursery_check (void)
1339 g_assert_not_reached ();
1344 mono_gc_get_nursery (int *shift_bits, size_t *size)
1350 mono_gc_precise_stack_mark_enabled (void)
1356 mono_gc_get_logfile (void)
1362 mono_gc_params_set (const char* options)
1367 mono_gc_debug_set (const char* options)
1372 mono_gc_conservatively_scan_area (void *start, void *end)
1374 g_assert_not_reached ();
1378 mono_gc_scan_object (void *obj, void *gc_data)
1380 g_assert_not_reached ();
1385 mono_gc_get_bitmap_for_descr (void *descr, int *numbits)
1387 g_assert_not_reached ();
1392 mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks)
1397 mono_gc_set_stack_end (void *stack_end)
1401 void mono_gc_set_skip_thread (gboolean value)
1406 mono_gc_register_for_finalization (MonoObject *obj, void *user_data)
1411 /* This assertion is not valid when GC_DEBUG is defined */
1412 g_assert (GC_base (obj) == (char*)obj - offset);
1415 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, (GC_finalization_proc)user_data, GUINT_TO_POINTER (offset), NULL, NULL);
1420 mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
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);
1429 BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reserved)
1431 return GC_DllMain (module_handle, reason, reserved);
1436 mono_gc_get_vtable_bits (MonoClass *klass)
1438 if (fin_callbacks.is_class_finalization_aware) {
1439 if (fin_callbacks.is_class_finalization_aware (klass))
1440 return BOEHM_GC_BIT_FINALIZER_AWARE;
1446 * mono_gc_register_altstack:
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.
1452 mono_gc_register_altstack (gpointer stack, gint32 stack_size, gpointer altstack, gint32 altstack_size)
1454 GC_register_altstack (stack, stack_size, altstack, altstack_size);
1458 mono_gc_get_los_limit (void)
1464 mono_gc_set_string_length (MonoString *str, gint32 new_length)
1466 mono_unichar2 *new_end = str->chars + new_length;
1468 /* zero the discarded string. This null-delimits the string and allows
1469 * the space to be reclaimed by SGen. */
1471 memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
1472 str->length = new_length;
1476 mono_gc_user_markers_supported (void)
1482 mono_gc_make_root_descr_user (MonoGCRootMarkFunc marker)
1484 g_assert_not_reached ();
1488 /* Toggleref support */
1491 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
1493 if (GC_toggleref_add ((GC_PTR)object, (int)strong_ref) != GC_SUCCESS)
1494 g_error ("GC_toggleref_add failed\n");
1498 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
1500 GC_set_toggleref_func ((GC_ToggleRefStatus (*) (GC_PTR obj)) proccess_toggleref);
1503 /* Test support code */
1505 static MonoToggleRefStatus
1506 test_toggleref_callback (MonoObject *obj)
1508 static MonoClassField *mono_toggleref_test_field;
1509 MonoToggleRefStatus status = MONO_TOGGLE_REF_DROP;
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);
1516 mono_field_get_value (obj, mono_toggleref_test_field, &status);
1517 printf ("toggleref-cb obj %d\n", status);
1522 register_test_toggleref_callback (void)
1524 mono_gc_toggleref_register_callback (test_toggleref_callback);
1528 is_finalization_aware (MonoObject *obj)
1530 MonoVTable *vt = obj->vtable;
1531 return (vt->gc_bits & BOEHM_GC_BIT_FINALIZER_AWARE) == BOEHM_GC_BIT_FINALIZER_AWARE;
1535 fin_notifier (MonoObject *obj)
1537 if (is_finalization_aware (obj))
1538 fin_callbacks.object_queued_for_finalization (obj);
1542 mono_gc_register_finalizer_callbacks (MonoGCFinalizerCallbacks *callbacks)
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);
1547 fin_callbacks = *callbacks;
1549 GC_set_await_finalize_proc ((void (*) (GC_PTR))fin_notifier);
1552 #define BITMAP_SIZE (sizeof (*((HandleData *)NULL)->bitmap) * CHAR_BIT)
1554 static inline gboolean
1555 slot_occupied (HandleData *handles, guint slot) {
1556 return handles->bitmap [slot / BITMAP_SIZE] & (1 << (slot % BITMAP_SIZE));
1560 vacate_slot (HandleData *handles, guint slot) {
1561 handles->bitmap [slot / BITMAP_SIZE] &= ~(1 << (slot % BITMAP_SIZE));
1565 occupy_slot (HandleData *handles, guint slot) {
1566 handles->bitmap [slot / BITMAP_SIZE] |= 1 << (slot % BITMAP_SIZE);
1570 find_first_unset (guint32 bitmap)
1573 for (i = 0; i < 32; ++i) {
1574 if (!(bitmap & (1 << i)))
1581 handle_data_alloc_entries (HandleData *handles)
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);
1588 handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1590 handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT);
1594 handle_data_next_unset (HandleData *handles)
1597 for (slot = handles->slot_hint; slot < handles->size / BITMAP_SIZE; ++slot) {
1598 if (handles->bitmap [slot] == 0xffffffff)
1600 handles->slot_hint = slot;
1601 return find_first_unset (handles->bitmap [slot]);
1607 handle_data_first_unset (HandleData *handles)
1610 for (slot = 0; slot < handles->slot_hint; ++slot) {
1611 if (handles->bitmap [slot] == 0xffffffff)
1613 handles->slot_hint = slot;
1614 return find_first_unset (handles->bitmap [slot]);
1619 /* Returns the index of the current slot in the bitmap. */
1621 handle_data_grow (HandleData *handles, gboolean track)
1623 guint32 *new_bitmap;
1624 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
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;
1632 /* resize and copy the entries */
1633 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1635 guint16 *domain_ids;
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]));
1643 mono_gc_weak_link_add (&(entries [i]), obj, track);
1644 mono_gc_weak_link_remove (&(handles->entries [i]), track);
1646 g_assert (!handles->entries [i]);
1649 g_free (handles->entries);
1650 g_free (handles->domain_ids);
1651 handles->entries = entries;
1652 handles->domain_ids = domain_ids;
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;
1660 handles->slot_hint = handles->size / BITMAP_SIZE;
1661 handles->size = new_size;
1665 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
1669 lock_handles (handles);
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);
1676 handle_data_grow (handles, track);
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;
1686 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
1688 handles->entries [slot] = obj;
1691 #ifndef DISABLE_PERFCOUNTERS
1692 mono_perfcounters->gc_num_handles++;
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);
1701 * mono_gchandle_new:
1702 * \param obj managed object to get a handle for
1703 * \param pinned whether the object should be pinned
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.
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
1714 * \returns a handle that can be used to access the object from
1718 mono_gchandle_new (MonoObject *obj, gboolean pinned)
1720 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
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.
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
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.
1741 * \returns a handle that can be used to access the object from
1745 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
1747 return alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
1751 * mono_gchandle_get_target:
1752 * \param gchandle a GCHandle's handle.
1754 * The handle was previously created by calling \c mono_gchandle_new or
1755 * \c mono_gchandle_new_weakref.
1757 * \returns A pointer to the \c MonoObject* represented by the handle or
1758 * NULL for a collected object if using a weakref handle.
1761 mono_gchandle_get_target (guint32 gchandle)
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)
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]);
1775 obj = (MonoObject *)handles->entries [slot];
1778 /* print a warning? */
1780 unlock_handles (handles);
1781 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
1786 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
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;
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);
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;
1805 handles->entries [slot] = obj;
1808 /* print a warning? */
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);
1815 mono_gc_is_null (void)
1821 * mono_gchandle_is_in_domain:
1822 * \param gchandle a GCHandle's handle.
1823 * \param domain An application domain.
1825 * Use this function to determine if the \p gchandle points to an
1826 * object allocated in the specified \p domain.
1828 * \returns TRUE if the object wrapped by the \p gchandle belongs to the specific \p domain.
1831 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
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;
1838 if (type >= HANDLE_TYPE_MAX)
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];
1847 obj = (MonoObject *)handles->entries [slot];
1851 result = domain == mono_object_domain (obj);
1854 /* print a warning? */
1856 unlock_handles (handles);
1861 * mono_gchandle_free:
1862 * \param gchandle a GCHandle's handle.
1864 * Frees the \p gchandle handle. If there are no outstanding
1865 * references, the garbage collector can reclaim the memory of the
1869 mono_gchandle_free (guint32 gchandle)
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)
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);
1883 handles->entries [slot] = NULL;
1885 vacate_slot (handles, slot);
1887 /* print a warning? */
1889 #ifndef DISABLE_PERFCOUNTERS
1890 mono_perfcounters->gc_num_handles--;
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);
1898 * mono_gchandle_free_domain:
1899 * \param domain domain that is unloading
1901 * Function used internally to cleanup any GC handle for objects belonging
1902 * to the specified domain during appdomain unload.
1905 mono_gchandle_free_domain (MonoDomain *domain)
1909 for (type = HANDLE_TYPE_MIN; type < HANDLE_PINNED; ++type) {
1911 HandleData *handles = &gc_handles [type];
1912 lock_handles (handles);
1913 for (slot = 0; slot < handles->size; ++slot) {
1914 if (!slot_occupied (handles, slot))
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);
1923 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
1924 vacate_slot (handles, slot);
1925 handles->entries [slot] = NULL;
1929 unlock_handles (handles);
1935 MONO_EMPTY_SOURCE_FILE (boehm_gc);
1936 #endif /* no Boehm GC */