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;
59 typedef void (*GC_push_other_roots_proc)(void);
61 static GC_push_other_roots_proc default_push_other_roots;
62 static GHashTable *roots;
65 mono_push_other_roots(void);
68 register_test_toggleref_callback (void);
70 #define BOEHM_GC_BIT_FINALIZER_AWARE 1
71 static MonoGCFinalizerCallbacks fin_callbacks;
75 static mono_mutex_t handle_section;
76 #define lock_handles(handles) mono_os_mutex_lock (&handle_section)
77 #define unlock_handles(handles) mono_os_mutex_unlock (&handle_section)
84 guint slot_hint : 24; /* starting slot for search in bitmap */
85 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
86 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
90 #define EMPTY_HANDLE_DATA(type) {NULL, NULL, 0, (type), 0, NULL}
92 /* weak and weak-track arrays will be allocated in malloc memory
94 static HandleData gc_handles [] = {
95 EMPTY_HANDLE_DATA (HANDLE_WEAK),
96 EMPTY_HANDLE_DATA (HANDLE_WEAK_TRACK),
97 EMPTY_HANDLE_DATA (HANDLE_NORMAL),
98 EMPTY_HANDLE_DATA (HANDLE_PINNED)
102 mono_gc_warning (char *msg, GC_word arg)
104 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_GC, msg, (unsigned long)arg);
107 static void on_gc_notification (GC_EventType event);
108 static void on_gc_heap_resize (size_t new_size);
111 mono_gc_base_init (void)
118 mono_counters_init ();
121 mono_w32handle_init ();
125 * Handle the case when we are called from a thread different from the main thread,
127 * FIXME: Move this to libgc where it belongs.
129 * we used to do this only when running on valgrind,
130 * but it happens also in other setups.
132 #if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
137 pthread_getattr_np (pthread_self (), &attr);
138 pthread_attr_getstack (&attr, &sstart, &size);
139 pthread_attr_destroy (&attr);
140 /*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/
141 /* apparently with some linuxthreads implementations sstart can be NULL,
142 * fallback to the more imprecise method (bug# 78096).
145 GC_stackbottom = (char*)sstart + size;
148 gsize stack_bottom = (gsize)&dummy;
149 stack_bottom += 4095;
150 stack_bottom &= ~4095;
151 GC_stackbottom = (char*)stack_bottom;
154 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
155 GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ());
156 #elif defined(__OpenBSD__)
157 # include <pthread_np.h>
162 rslt = pthread_stackseg_np(pthread_self(), &ss);
163 g_assert (rslt == 0);
165 GC_stackbottom = (char*)ss.ss_sp;
170 gsize stack_bottom = (gsize)&dummy;
171 stack_bottom += 4095;
172 stack_bottom &= ~4095;
173 /*g_print ("stackbottom is: %p\n", (char*)stack_bottom);*/
174 GC_stackbottom = (char*)stack_bottom;
178 roots = g_hash_table_new (NULL, NULL);
179 default_push_other_roots = GC_push_other_roots;
180 GC_push_other_roots = mono_push_other_roots;
182 #if !defined(PLATFORM_ANDROID)
183 /* If GC_no_dls is set to true, GC_find_limit is not called. This causes a seg fault on Android. */
187 if ((env = g_getenv ("MONO_GC_DEBUG"))) {
188 char **opts = g_strsplit (env, ",", -1);
189 for (char **ptr = opts; ptr && *ptr; ptr ++) {
191 if (!strcmp (opt, "do-not-finalize")) {
192 mono_do_not_finalize = 1;
193 } else if (!strcmp (opt, "log-finalizers")) {
203 GC_set_warn_proc (mono_gc_warning);
204 GC_finalize_on_demand = 1;
205 GC_finalizer_notifier = mono_gc_finalize_notify;
207 GC_init_gcj_malloc (5, NULL);
208 GC_allow_register_threads ();
210 if ((env = g_getenv ("MONO_GC_PARAMS"))) {
211 char **ptr, **opts = g_strsplit (env, ",", -1);
212 for (ptr = opts; *ptr; ++ptr) {
214 if (g_str_has_prefix (opt, "max-heap-size=")) {
217 opt = strchr (opt, '=') + 1;
218 if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap)) {
219 if (max_heap < MIN_BOEHM_MAX_HEAP_SIZE) {
220 fprintf (stderr, "max-heap-size must be at least %dMb.\n", MIN_BOEHM_MAX_HEAP_SIZE_IN_MB);
223 GC_set_max_heap_size (max_heap);
225 fprintf (stderr, "max-heap-size must be an integer.\n");
229 } else if (g_str_has_prefix (opt, "toggleref-test")) {
230 register_test_toggleref_callback ();
233 /* Could be a parameter for sgen */
235 fprintf (stderr, "MONO_GC_PARAMS must be a comma-delimited list of one or more of the following:\n");
236 fprintf (stderr, " max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
245 mono_thread_callbacks_init ();
246 mono_thread_info_init (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 mono_gc_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 mono_gc_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 mono_gc_thread_in_critical_region (MonoThreadInfo *info)
415 mono_object_is_alive (MonoObject* o)
417 return GC_is_marked ((ptr_t)o);
421 mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
426 static gint64 gc_start_time;
429 on_gc_notification (GC_EventType event)
431 MonoProfilerGCEvent e;
434 case GC_EVENT_PRE_STOP_WORLD:
435 e = MONO_GC_EVENT_PRE_STOP_WORLD;
436 MONO_GC_WORLD_STOP_BEGIN ();
439 case GC_EVENT_POST_STOP_WORLD:
440 e = MONO_GC_EVENT_POST_STOP_WORLD;
441 MONO_GC_WORLD_STOP_END ();
444 case GC_EVENT_PRE_START_WORLD:
445 e = MONO_GC_EVENT_PRE_START_WORLD;
446 MONO_GC_WORLD_RESTART_BEGIN (1);
449 case GC_EVENT_POST_START_WORLD:
450 e = MONO_GC_EVENT_POST_START_WORLD;
451 MONO_GC_WORLD_RESTART_END (1);
455 e = MONO_GC_EVENT_START;
457 #ifndef DISABLE_PERFCOUNTERS
458 if (mono_perfcounters)
459 mono_perfcounters->gc_collections0++;
461 gc_stats.major_gc_count ++;
462 gc_start_time = mono_100ns_ticks ();
466 e = MONO_GC_EVENT_END;
468 #if defined(ENABLE_DTRACE) && defined(__sun__)
469 /* This works around a dtrace -G problem on Solaris.
470 Limit its actual use to when the probe is enabled. */
471 if (MONO_GC_END_ENABLED ())
475 #ifndef DISABLE_PERFCOUNTERS
476 if (mono_perfcounters) {
477 guint64 heap_size = GC_get_heap_size ();
478 guint64 used_size = heap_size - GC_get_free_bytes ();
479 mono_perfcounters->gc_total_bytes = used_size;
480 mono_perfcounters->gc_committed_bytes = heap_size;
481 mono_perfcounters->gc_reserved_bytes = heap_size;
482 mono_perfcounters->gc_gen0size = heap_size;
485 gc_stats.major_gc_time += mono_100ns_ticks () - gc_start_time;
486 mono_trace_message (MONO_TRACE_GC, "gc took %" G_GINT64_FORMAT " usecs", (mono_100ns_ticks () - gc_start_time) / 10);
493 case GC_EVENT_MARK_START:
494 case GC_EVENT_MARK_END:
495 case GC_EVENT_RECLAIM_START:
496 case GC_EVENT_RECLAIM_END:
499 MONO_PROFILER_RAISE (gc_event, (e, 0));
504 case GC_EVENT_PRE_STOP_WORLD:
505 mono_thread_info_suspend_lock ();
506 MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0));
508 case GC_EVENT_POST_START_WORLD:
509 mono_thread_info_suspend_unlock ();
510 MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0));
519 on_gc_heap_resize (size_t new_size)
521 guint64 heap_size = GC_get_heap_size ();
522 #ifndef DISABLE_PERFCOUNTERS
523 if (mono_perfcounters) {
524 mono_perfcounters->gc_committed_bytes = heap_size;
525 mono_perfcounters->gc_reserved_bytes = heap_size;
526 mono_perfcounters->gc_gen0size = heap_size;
530 MONO_PROFILER_RAISE (gc_resize, (new_size));
539 register_root (gpointer arg)
541 RootData* root_data = arg;
542 g_hash_table_insert (roots, root_data->start, root_data->end);
547 mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg)
550 root_data.start = start;
551 /* Boehm root processing requires one byte past end of region to be scanned */
552 root_data.end = start + size + 1;
553 GC_call_with_alloc_lock (register_root, &root_data);
559 mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg)
561 return mono_gc_register_root (start, size, descr, source, msg);
565 deregister_root (gpointer arg)
567 gboolean removed = g_hash_table_remove (roots, arg);
573 mono_gc_deregister_root (char* addr)
575 GC_call_with_alloc_lock (deregister_root, addr);
579 push_root (gpointer key, gpointer value, gpointer user_data)
581 GC_push_all (key, value);
585 mono_push_other_roots (void)
587 g_hash_table_foreach (roots, push_root, NULL);
588 if (default_push_other_roots)
589 default_push_other_roots ();
593 mono_gc_weak_link_add (void **link_addr, MonoObject *obj, gboolean track)
595 /* libgc requires that we use HIDE_POINTER... */
596 *link_addr = (void*)HIDE_POINTER (obj);
598 GC_REGISTER_LONG_LINK (link_addr, obj);
600 GC_GENERAL_REGISTER_DISAPPEARING_LINK (link_addr, obj);
604 mono_gc_weak_link_remove (void **link_addr, gboolean track)
607 GC_unregister_long_link (link_addr);
609 GC_unregister_disappearing_link (link_addr);
614 reveal_link (gpointer link_addr)
616 void **link_a = (void **)link_addr;
617 return REVEAL_POINTER (*link_a);
621 mono_gc_weak_link_get (void **link_addr)
623 MonoObject *obj = (MonoObject *)GC_call_with_alloc_lock (reveal_link, link_addr);
624 if (obj == (MonoObject *) -1)
630 mono_gc_make_descr_for_string (gsize *bitmap, int numbits)
632 return mono_gc_make_descr_from_bitmap (bitmap, numbits);
636 mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
638 return mono_gc_make_descr_from_bitmap (bitmap, numbits);
642 mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size)
644 /* libgc has no usable support for arrays... */
645 return GC_NO_DESCRIPTOR;
649 mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits)
651 /* It seems there are issues when the bitmap doesn't fit: play it safe */
653 return GC_NO_DESCRIPTOR;
655 return (gpointer)GC_make_descriptor ((GC_bitmap)bitmap, numbits);
659 mono_gc_make_vector_descr (void)
665 mono_gc_make_root_descr_all_refs (int numbits)
671 mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, const char *msg)
673 return GC_MALLOC_UNCOLLECTABLE (size);
677 mono_gc_free_fixed (void* addr)
683 mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
687 if (!vtable->klass->has_references) {
688 obj = (MonoObject *)GC_MALLOC_ATOMIC (size);
689 if (G_UNLIKELY (!obj))
692 obj->vtable = vtable;
693 obj->synchronisation = NULL;
695 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
696 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
697 obj = (MonoObject *)GC_GCJ_MALLOC (size, vtable);
698 if (G_UNLIKELY (!obj))
701 obj = (MonoObject *)GC_MALLOC (size);
702 if (G_UNLIKELY (!obj))
705 obj->vtable = vtable;
708 if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
709 MONO_PROFILER_RAISE (gc_allocation, (obj));
715 mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
719 if (!vtable->klass->has_references) {
720 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
721 if (G_UNLIKELY (!obj))
724 obj->obj.vtable = vtable;
725 obj->obj.synchronisation = NULL;
727 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
728 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
729 obj = (MonoArray *)GC_GCJ_MALLOC (size, vtable);
730 if (G_UNLIKELY (!obj))
733 obj = (MonoArray *)GC_MALLOC (size);
734 if (G_UNLIKELY (!obj))
737 obj->obj.vtable = vtable;
740 obj->max_length = max_length;
742 if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
743 MONO_PROFILER_RAISE (gc_allocation, (&obj->obj));
749 mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uintptr_t bounds_size)
753 if (!vtable->klass->has_references) {
754 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
755 if (G_UNLIKELY (!obj))
758 obj->obj.vtable = vtable;
759 obj->obj.synchronisation = NULL;
761 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
762 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
763 obj = (MonoArray *)GC_GCJ_MALLOC (size, vtable);
764 if (G_UNLIKELY (!obj))
767 obj = (MonoArray *)GC_MALLOC (size);
768 if (G_UNLIKELY (!obj))
771 obj->obj.vtable = vtable;
774 obj->max_length = max_length;
777 obj->bounds = (MonoArrayBounds *) ((char *) obj + size - bounds_size);
779 if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
780 MONO_PROFILER_RAISE (gc_allocation, (&obj->obj));
786 mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
788 MonoString *obj = (MonoString *)GC_MALLOC_ATOMIC (size);
789 if (G_UNLIKELY (!obj))
792 obj->object.vtable = vtable;
793 obj->object.synchronisation = NULL;
795 obj->chars [len] = 0;
797 if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
798 MONO_PROFILER_RAISE (gc_allocation, (&obj->object));
804 mono_gc_alloc_mature (MonoVTable *vtable, size_t size)
806 return mono_gc_alloc_obj (vtable, size);
810 mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size)
812 return mono_gc_alloc_obj (vtable, size);
816 mono_gc_invoke_finalizers (void)
818 /* There is a bug in GC_invoke_finalizer () in versions <= 6.2alpha4:
819 * the 'mem_freed' variable is not initialized when there are no
820 * objects to finalize, which leads to strange behavior later on.
821 * The check is necessary to work around that bug.
823 if (GC_should_invoke_finalizers ())
824 return GC_invoke_finalizers ();
829 mono_gc_pending_finalizers (void)
831 return GC_should_invoke_finalizers ();
835 mono_gc_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* value)
837 *(void**)field_ptr = value;
841 mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* value)
843 *(void**)slot_ptr = value;
847 mono_gc_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
849 mono_gc_memmove_aligned (dest_ptr, src_ptr, count * sizeof (gpointer));
853 mono_gc_wbarrier_generic_store (gpointer ptr, MonoObject* value)
855 *(void**)ptr = value;
859 mono_gc_wbarrier_generic_store_atomic (gpointer ptr, MonoObject *value)
861 InterlockedWritePointer ((volatile gpointer *)ptr, value);
865 mono_gc_wbarrier_generic_nostore (gpointer ptr)
870 mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass)
872 mono_gc_memmove_atomic (dest, src, count * mono_class_value_size (klass, NULL));
876 mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
878 /* do not copy the sync state */
879 mono_gc_memmove_aligned ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject),
880 mono_object_class (obj)->instance_size - sizeof (MonoObject));
884 mono_gc_clear_domain (MonoDomain *domain)
889 mono_gc_suspend_finalizers (void)
894 mono_gc_get_suspend_signal (void)
896 return GC_get_suspend_signal ();
900 mono_gc_get_restart_signal (void)
902 return GC_get_thr_restart_signal ();
905 #if defined(USE_COMPILER_TLS) && defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
906 extern __thread void* GC_thread_tls;
907 #include "metadata-internals.h"
913 while (!(v & (1 << i)))
920 ATYPE_FREEPTR_FOR_BOX,
928 create_allocator (int atype, int tls_key, gboolean slowpath)
930 int index_var, bytes_var, my_fl_var, my_entry_var;
931 guint32 no_freelist_branch, not_small_enough_branch = 0;
932 guint32 size_overflow_branch = 0;
933 MonoMethodBuilder *mb;
935 MonoMethodSignature *csig;
936 const char *name = NULL;
939 g_assert_not_reached ();
941 if (atype == ATYPE_FREEPTR) {
942 name = slowpath ? "SlowAllocPtrfree" : "AllocPtrfree";
943 } else if (atype == ATYPE_FREEPTR_FOR_BOX) {
944 name = slowpath ? "SlowAllocPtrfreeBox" : "AllocPtrfreeBox";
945 } else if (atype == ATYPE_NORMAL) {
946 name = slowpath ? "SlowAlloc" : "Alloc";
947 } else if (atype == ATYPE_GCJ) {
948 name = slowpath ? "SlowAllocGcj" : "AllocGcj";
949 } else if (atype == ATYPE_STRING) {
950 name = slowpath ? "SlowAllocString" : "AllocString";
952 g_assert_not_reached ();
955 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
957 if (atype == ATYPE_STRING) {
958 csig->ret = &mono_defaults.string_class->byval_arg;
959 csig->params [0] = &mono_defaults.int_class->byval_arg;
960 csig->params [1] = &mono_defaults.int32_class->byval_arg;
962 csig->ret = &mono_defaults.object_class->byval_arg;
963 csig->params [0] = &mono_defaults.int_class->byval_arg;
964 csig->params [1] = &mono_defaults.int32_class->byval_arg;
967 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ALLOC);
970 goto always_slowpath;
972 bytes_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
973 if (atype == ATYPE_STRING) {
974 /* a string alloator method takes the args: (vtable, len) */
975 /* bytes = (offsetof (MonoString, chars) + ((len + 1) * 2)); */
976 mono_mb_emit_ldarg (mb, 1);
977 mono_mb_emit_icon (mb, 1);
978 mono_mb_emit_byte (mb, MONO_CEE_ADD);
979 mono_mb_emit_icon (mb, 1);
980 mono_mb_emit_byte (mb, MONO_CEE_SHL);
981 // sizeof (MonoString) might include padding
982 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoString, chars));
983 mono_mb_emit_byte (mb, MONO_CEE_ADD);
984 mono_mb_emit_stloc (mb, bytes_var);
986 mono_mb_emit_ldarg (mb, 1);
987 mono_mb_emit_stloc (mb, bytes_var);
990 /* this is needed for strings/arrays only as the other big types are never allocated with this method */
991 if (atype == ATYPE_STRING) {
993 /* if (!SMALL_ENOUGH (bytes)) jump slow_path;*/
994 mono_mb_emit_ldloc (mb, bytes_var);
995 mono_mb_emit_icon (mb, (NFREELISTS-1) * GRANULARITY);
996 not_small_enough_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BGT_UN_S);
997 /* check for overflow */
998 mono_mb_emit_ldloc (mb, bytes_var);
999 mono_mb_emit_icon (mb, sizeof (MonoString));
1000 size_overflow_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLE_UN_S);
1003 /* int index = INDEX_FROM_BYTES(bytes); */
1004 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
1006 mono_mb_emit_ldloc (mb, bytes_var);
1007 mono_mb_emit_icon (mb, GRANULARITY - 1);
1008 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1009 mono_mb_emit_icon (mb, shift_amount (GRANULARITY));
1010 mono_mb_emit_byte (mb, MONO_CEE_SHR_UN);
1011 mono_mb_emit_icon (mb, shift_amount (sizeof (gpointer)));
1012 mono_mb_emit_byte (mb, MONO_CEE_SHL);
1013 /* index var is already adjusted into bytes */
1014 mono_mb_emit_stloc (mb, index_var);
1016 my_fl_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1017 my_entry_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1018 /* my_fl = ((GC_thread)tsd) -> ptrfree_freelists + index; */
1019 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1020 mono_mb_emit_byte (mb, 0x0D); /* CEE_MONO_TLS */
1021 mono_mb_emit_i4 (mb, tls_key);
1022 if (atype == ATYPE_FREEPTR || atype == ATYPE_FREEPTR_FOR_BOX || atype == ATYPE_STRING)
1023 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
1024 + G_STRUCT_OFFSET (struct thread_local_freelists,
1025 ptrfree_freelists));
1026 else if (atype == ATYPE_NORMAL)
1027 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
1028 + G_STRUCT_OFFSET (struct thread_local_freelists,
1030 else if (atype == ATYPE_GCJ)
1031 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
1032 + G_STRUCT_OFFSET (struct thread_local_freelists,
1035 g_assert_not_reached ();
1036 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1037 mono_mb_emit_ldloc (mb, index_var);
1038 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1039 mono_mb_emit_stloc (mb, my_fl_var);
1041 /* my_entry = *my_fl; */
1042 mono_mb_emit_ldloc (mb, my_fl_var);
1043 mono_mb_emit_byte (mb, MONO_CEE_LDIND_I);
1044 mono_mb_emit_stloc (mb, my_entry_var);
1046 /* if (EXPECT((word)my_entry >= HBLKSIZE, 1)) { */
1047 mono_mb_emit_ldloc (mb, my_entry_var);
1048 mono_mb_emit_icon (mb, HBLKSIZE);
1049 no_freelist_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLT_UN_S);
1051 /* ptr_t next = obj_link(my_entry); *my_fl = next; */
1052 mono_mb_emit_ldloc (mb, my_fl_var);
1053 mono_mb_emit_ldloc (mb, my_entry_var);
1054 mono_mb_emit_byte (mb, MONO_CEE_LDIND_I);
1055 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1057 /* set the vtable and clear the words in the object */
1058 mono_mb_emit_ldloc (mb, my_entry_var);
1059 mono_mb_emit_ldarg (mb, 0);
1060 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1062 if (atype == ATYPE_FREEPTR) {
1063 int start_var, end_var, start_loop;
1064 /* end = my_entry + bytes; start = my_entry + sizeof (gpointer);
1066 start_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1067 end_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1068 mono_mb_emit_ldloc (mb, my_entry_var);
1069 mono_mb_emit_ldloc (mb, bytes_var);
1070 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1071 mono_mb_emit_stloc (mb, end_var);
1072 mono_mb_emit_ldloc (mb, my_entry_var);
1073 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoObject, synchronisation));
1074 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1075 mono_mb_emit_stloc (mb, start_var);
1079 * } while (start < end);
1081 start_loop = mono_mb_get_label (mb);
1082 mono_mb_emit_ldloc (mb, start_var);
1083 mono_mb_emit_icon (mb, 0);
1084 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1085 mono_mb_emit_ldloc (mb, start_var);
1086 mono_mb_emit_icon (mb, sizeof (gpointer));
1087 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1088 mono_mb_emit_stloc (mb, start_var);
1090 mono_mb_emit_ldloc (mb, start_var);
1091 mono_mb_emit_ldloc (mb, end_var);
1092 mono_mb_emit_byte (mb, MONO_CEE_BLT_UN_S);
1093 mono_mb_emit_byte (mb, start_loop - (mono_mb_get_label (mb) + 1));
1094 } else if (atype == ATYPE_FREEPTR_FOR_BOX || atype == ATYPE_STRING) {
1095 /* need to clear just the sync pointer */
1096 mono_mb_emit_ldloc (mb, my_entry_var);
1097 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoObject, synchronisation));
1098 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1099 mono_mb_emit_icon (mb, 0);
1100 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1103 if (atype == ATYPE_STRING) {
1104 /* need to set length and clear the last char */
1105 /* s->length = len; */
1106 mono_mb_emit_ldloc (mb, my_entry_var);
1107 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoString, length));
1108 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1109 mono_mb_emit_ldarg (mb, 1);
1110 mono_mb_emit_byte (mb, MONO_CEE_STIND_I4);
1111 /* s->chars [len] = 0; */
1112 mono_mb_emit_ldloc (mb, my_entry_var);
1113 mono_mb_emit_ldloc (mb, bytes_var);
1114 mono_mb_emit_icon (mb, 2);
1115 mono_mb_emit_byte (mb, MONO_CEE_SUB);
1116 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1117 mono_mb_emit_icon (mb, 0);
1118 mono_mb_emit_byte (mb, MONO_CEE_STIND_I2);
1121 /* return my_entry; */
1122 mono_mb_emit_ldloc (mb, my_entry_var);
1123 mono_mb_emit_byte (mb, MONO_CEE_RET);
1125 mono_mb_patch_short_branch (mb, no_freelist_branch);
1126 if (not_small_enough_branch > 0)
1127 mono_mb_patch_short_branch (mb, not_small_enough_branch);
1128 if (size_overflow_branch > 0)
1129 mono_mb_patch_short_branch (mb, size_overflow_branch);
1131 /* the slow path: we just call back into the runtime */
1133 if (atype == ATYPE_STRING) {
1134 mono_mb_emit_ldarg (mb, 1);
1135 mono_mb_emit_icall (mb, ves_icall_string_alloc);
1137 mono_mb_emit_ldarg (mb, 0);
1138 mono_mb_emit_icall (mb, ves_icall_object_new_specific);
1141 mono_mb_emit_byte (mb, MONO_CEE_RET);
1143 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1144 info->d.alloc.gc_name = "boehm";
1145 info->d.alloc.alloc_type = atype;
1146 mb->init_locals = FALSE;
1148 res = mono_mb_create (mb, csig, 8, info);
1154 static MonoMethod* alloc_method_cache [ATYPE_NUM];
1155 static MonoMethod* slowpath_alloc_method_cache [ATYPE_NUM];
1158 mono_gc_is_critical_method (MonoMethod *method)
1162 for (i = 0; i < ATYPE_NUM; ++i)
1163 if (method == alloc_method_cache [i] || method == slowpath_alloc_method_cache [i])
1170 * If possible, generate a managed method that can quickly allocate objects in class
1171 * @klass. The method will typically have an thread-local inline allocation sequence.
1172 * The signature of the called method is:
1173 * object allocate (MonoVTable *vtable)
1174 * The thread local alloc logic is taken from libgc/pthread_support.c.
1177 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1182 * Tls implementation changed, we jump to tls native getters/setters.
1183 * Is boehm managed allocator ok with this ? Do we even care ?
1187 if (!SMALL_ENOUGH (klass->instance_size))
1189 if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass))
1191 if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
1195 if (mono_class_is_open_constructed_type (&klass->byval_arg))
1197 if (klass->byval_arg.type == MONO_TYPE_STRING) {
1198 atype = ATYPE_STRING;
1199 } else if (!known_instance_size) {
1201 } else if (!klass->has_references) {
1203 atype = ATYPE_FREEPTR_FOR_BOX;
1205 atype = ATYPE_FREEPTR;
1209 * disabled because we currently do a runtime choice anyway, to
1210 * deal with multiple appdomains.
1211 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1214 atype = ATYPE_NORMAL;
1217 return mono_gc_get_managed_allocator_by_type (atype, MANAGED_ALLOCATOR_REGULAR);
1221 mono_gc_get_managed_array_allocator (MonoClass *klass)
1227 * mono_gc_get_managed_allocator_by_type:
1229 * Return a managed allocator method corresponding to allocator type ATYPE.
1232 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1235 gboolean slowpath = variant != MANAGED_ALLOCATOR_REGULAR;
1236 MonoMethod **cache = slowpath ? slowpath_alloc_method_cache : alloc_method_cache;
1240 res = cache [atype];
1244 res = create_allocator (atype, -1, slowpath);
1245 mono_os_mutex_lock (&mono_gc_lock);
1246 if (cache [atype]) {
1247 mono_free_method (res);
1248 res = cache [atype];
1250 mono_memory_barrier ();
1251 cache [atype] = res;
1253 mono_os_mutex_unlock (&mono_gc_lock);
1258 mono_gc_get_managed_allocator_types (void)
1264 mono_gc_get_write_barrier (void)
1266 g_assert_not_reached ();
1273 mono_gc_is_critical_method (MonoMethod *method)
1279 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1285 mono_gc_get_managed_array_allocator (MonoClass *klass)
1291 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1297 mono_gc_get_managed_allocator_types (void)
1303 mono_gc_get_write_barrier (void)
1305 g_assert_not_reached ();
1312 mono_gc_get_specific_write_barrier (gboolean is_concurrent)
1314 g_assert_not_reached ();
1319 mono_gc_get_aligned_size_for_allocator (int size)
1325 mono_gc_get_gc_name (void)
1331 mono_gc_invoke_with_gc_lock (MonoGCLockedCallbackFunc func, void *data)
1333 return GC_call_with_alloc_lock (func, data);
1337 mono_gc_get_description (void)
1339 return g_strdup (DEFAULT_GC_NAME);
1343 mono_gc_set_desktop_mode (void)
1349 mono_gc_is_moving (void)
1355 mono_gc_is_disabled (void)
1357 if (GC_dont_gc || g_hasenv ("GC_DONT_GC"))
1364 mono_gc_wbarrier_range_copy (gpointer _dest, gpointer _src, int size)
1366 g_assert_not_reached ();
1370 mono_gc_get_range_copy_func (void)
1372 return &mono_gc_wbarrier_range_copy;
1376 mono_gc_get_card_table (int *shift_bits, gpointer *card_mask)
1378 g_assert_not_reached ();
1383 mono_gc_card_table_nursery_check (void)
1385 g_assert_not_reached ();
1390 mono_gc_get_nursery (int *shift_bits, size_t *size)
1396 mono_gc_precise_stack_mark_enabled (void)
1402 mono_gc_get_logfile (void)
1408 mono_gc_params_set (const char* options)
1413 mono_gc_debug_set (const char* options)
1418 mono_gc_conservatively_scan_area (void *start, void *end)
1420 g_assert_not_reached ();
1424 mono_gc_scan_object (void *obj, void *gc_data)
1426 g_assert_not_reached ();
1431 mono_gc_get_bitmap_for_descr (void *descr, int *numbits)
1433 g_assert_not_reached ();
1438 mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks)
1443 mono_gc_set_stack_end (void *stack_end)
1447 void mono_gc_set_skip_thread (gboolean value)
1452 mono_gc_register_for_finalization (MonoObject *obj, void *user_data)
1457 /* This assertion is not valid when GC_DEBUG is defined */
1458 g_assert (GC_base (obj) == (char*)obj - offset);
1461 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, (GC_finalization_proc)user_data, GUINT_TO_POINTER (offset), NULL, NULL);
1466 mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
1468 /* it is being replaced by GC_pthread_create on some
1469 * platforms, see libgc/include/gc_pthread_redirects.h */
1470 return pthread_create (new_thread, attr, start_routine, arg);
1475 BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reserved)
1477 return GC_DllMain (module_handle, reason, reserved);
1482 mono_gc_get_vtable_bits (MonoClass *klass)
1484 if (fin_callbacks.is_class_finalization_aware) {
1485 if (fin_callbacks.is_class_finalization_aware (klass))
1486 return BOEHM_GC_BIT_FINALIZER_AWARE;
1492 * mono_gc_register_altstack:
1494 * Register the dimensions of the normal stack and altstack with the collector.
1495 * Currently, STACK/STACK_SIZE is only used when the thread is suspended while it is on an altstack.
1498 mono_gc_register_altstack (gpointer stack, gint32 stack_size, gpointer altstack, gint32 altstack_size)
1500 GC_register_altstack (stack, stack_size, altstack, altstack_size);
1504 mono_gc_get_los_limit (void)
1510 mono_gc_set_string_length (MonoString *str, gint32 new_length)
1512 mono_unichar2 *new_end = str->chars + new_length;
1514 /* zero the discarded string. This null-delimits the string and allows
1515 * the space to be reclaimed by SGen. */
1517 memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
1518 str->length = new_length;
1522 mono_gc_user_markers_supported (void)
1528 mono_gc_make_root_descr_user (MonoGCRootMarkFunc marker)
1530 g_assert_not_reached ();
1534 /* Toggleref support */
1537 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
1539 if (GC_toggleref_add ((GC_PTR)object, (int)strong_ref) != GC_SUCCESS)
1540 g_error ("GC_toggleref_add failed\n");
1544 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
1546 GC_set_toggleref_func ((GC_ToggleRefStatus (*) (GC_PTR obj)) proccess_toggleref);
1549 /* Test support code */
1551 static MonoToggleRefStatus
1552 test_toggleref_callback (MonoObject *obj)
1554 static MonoClassField *mono_toggleref_test_field;
1555 MonoToggleRefStatus status = MONO_TOGGLE_REF_DROP;
1557 if (!mono_toggleref_test_field) {
1558 mono_toggleref_test_field = mono_class_get_field_from_name (mono_object_get_class (obj), "__test");
1559 g_assert (mono_toggleref_test_field);
1562 mono_field_get_value (obj, mono_toggleref_test_field, &status);
1563 printf ("toggleref-cb obj %d\n", status);
1568 register_test_toggleref_callback (void)
1570 mono_gc_toggleref_register_callback (test_toggleref_callback);
1574 is_finalization_aware (MonoObject *obj)
1576 MonoVTable *vt = obj->vtable;
1577 return (vt->gc_bits & BOEHM_GC_BIT_FINALIZER_AWARE) == BOEHM_GC_BIT_FINALIZER_AWARE;
1581 fin_notifier (MonoObject *obj)
1583 if (is_finalization_aware (obj))
1584 fin_callbacks.object_queued_for_finalization (obj);
1588 mono_gc_register_finalizer_callbacks (MonoGCFinalizerCallbacks *callbacks)
1590 if (callbacks->version != MONO_GC_FINALIZER_EXTENSION_VERSION)
1591 g_error ("Invalid finalizer callback version. Expected %d but got %d\n", MONO_GC_FINALIZER_EXTENSION_VERSION, callbacks->version);
1593 fin_callbacks = *callbacks;
1595 GC_set_await_finalize_proc ((void (*) (GC_PTR))fin_notifier);
1598 #define BITMAP_SIZE (sizeof (*((HandleData *)NULL)->bitmap) * CHAR_BIT)
1600 static inline gboolean
1601 slot_occupied (HandleData *handles, guint slot) {
1602 return handles->bitmap [slot / BITMAP_SIZE] & (1 << (slot % BITMAP_SIZE));
1606 vacate_slot (HandleData *handles, guint slot) {
1607 handles->bitmap [slot / BITMAP_SIZE] &= ~(1 << (slot % BITMAP_SIZE));
1611 occupy_slot (HandleData *handles, guint slot) {
1612 handles->bitmap [slot / BITMAP_SIZE] |= 1 << (slot % BITMAP_SIZE);
1616 find_first_unset (guint32 bitmap)
1619 for (i = 0; i < 32; ++i) {
1620 if (!(bitmap & (1 << i)))
1627 handle_data_alloc_entries (HandleData *handles)
1630 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1631 handles->entries = (void **)g_malloc0 (sizeof (*handles->entries) * handles->size);
1632 handles->domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * handles->size);
1634 handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1636 handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT);
1640 handle_data_next_unset (HandleData *handles)
1643 for (slot = handles->slot_hint; slot < handles->size / BITMAP_SIZE; ++slot) {
1644 if (handles->bitmap [slot] == 0xffffffff)
1646 handles->slot_hint = slot;
1647 return find_first_unset (handles->bitmap [slot]);
1653 handle_data_first_unset (HandleData *handles)
1656 for (slot = 0; slot < handles->slot_hint; ++slot) {
1657 if (handles->bitmap [slot] == 0xffffffff)
1659 handles->slot_hint = slot;
1660 return find_first_unset (handles->bitmap [slot]);
1665 /* Returns the index of the current slot in the bitmap. */
1667 handle_data_grow (HandleData *handles, gboolean track)
1669 guint32 *new_bitmap;
1670 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
1672 /* resize and copy the bitmap */
1673 new_bitmap = (guint32 *)g_malloc0 (new_size / CHAR_BIT);
1674 memcpy (new_bitmap, handles->bitmap, handles->size / CHAR_BIT);
1675 g_free (handles->bitmap);
1676 handles->bitmap = new_bitmap;
1678 /* resize and copy the entries */
1679 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1681 guint16 *domain_ids;
1683 domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * new_size);
1684 entries = (void **)g_malloc0 (sizeof (*handles->entries) * new_size);
1685 memcpy (domain_ids, handles->domain_ids, sizeof (*handles->domain_ids) * handles->size);
1686 for (i = 0; i < handles->size; ++i) {
1687 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
1689 mono_gc_weak_link_add (&(entries [i]), obj, track);
1690 mono_gc_weak_link_remove (&(handles->entries [i]), track);
1692 g_assert (!handles->entries [i]);
1695 g_free (handles->entries);
1696 g_free (handles->domain_ids);
1697 handles->entries = entries;
1698 handles->domain_ids = domain_ids;
1701 entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1702 mono_gc_memmove_aligned (entries, handles->entries, sizeof (*handles->entries) * handles->size);
1703 mono_gc_free_fixed (handles->entries);
1704 handles->entries = entries;
1706 handles->slot_hint = handles->size / BITMAP_SIZE;
1707 handles->size = new_size;
1711 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
1715 lock_handles (handles);
1717 handle_data_alloc_entries (handles);
1718 i = handle_data_next_unset (handles);
1719 if (i == -1 && handles->slot_hint != 0)
1720 i = handle_data_first_unset (handles);
1722 handle_data_grow (handles, track);
1725 slot = handles->slot_hint * BITMAP_SIZE + i;
1726 occupy_slot (handles, slot);
1727 handles->entries [slot] = NULL;
1728 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1729 /*FIXME, what to use when obj == null?*/
1730 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1732 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
1734 handles->entries [slot] = obj;
1737 #ifndef DISABLE_PERFCOUNTERS
1738 mono_perfcounters->gc_num_handles++;
1740 unlock_handles (handles);
1741 res = MONO_GC_HANDLE (slot, handles->type);
1742 MONO_PROFILER_RAISE (gc_handle_created, (res, handles->type, obj));
1747 * mono_gchandle_new:
1748 * \param obj managed object to get a handle for
1749 * \param pinned whether the object should be pinned
1751 * This returns a handle that wraps the object, this is used to keep a
1752 * reference to a managed object from the unmanaged world and preventing the
1753 * object from being disposed.
1755 * If \p pinned is false the address of the object can not be obtained, if it is
1756 * true the address of the object can be obtained. This will also pin the
1757 * object so it will not be possible by a moving garbage collector to move the
1760 * \returns a handle that can be used to access the object from
1764 mono_gchandle_new (MonoObject *obj, gboolean pinned)
1766 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
1770 * mono_gchandle_new_weakref:
1771 * \param obj managed object to get a handle for
1772 * \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.
1774 * This returns a weak handle that wraps the object, this is used to
1775 * keep a reference to a managed object from the unmanaged world.
1776 * Unlike the \c mono_gchandle_new the object can be reclaimed by the
1777 * garbage collector. In this case the value of the GCHandle will be
1780 * If \p track_resurrection is TRUE the object will be tracked through
1781 * finalization and if the object is resurrected during the execution
1782 * of the finalizer, then the returned weakref will continue to hold
1783 * a reference to the object. If \p track_resurrection is FALSE, then
1784 * the weak reference's target will become NULL as soon as the object
1785 * is passed on to the finalizer.
1787 * \returns a handle that can be used to access the object from
1791 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
1793 return alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
1797 * mono_gchandle_get_target:
1798 * \param gchandle a GCHandle's handle.
1800 * The handle was previously created by calling \c mono_gchandle_new or
1801 * \c mono_gchandle_new_weakref.
1803 * \returns A pointer to the \c MonoObject* represented by the handle or
1804 * NULL for a collected object if using a weakref handle.
1807 mono_gchandle_get_target (guint32 gchandle)
1809 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1810 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1811 HandleData *handles = &gc_handles [type];
1812 MonoObject *obj = NULL;
1813 if (type >= HANDLE_TYPE_MAX)
1816 lock_handles (handles);
1817 if (slot < handles->size && slot_occupied (handles, slot)) {
1818 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1819 obj = mono_gc_weak_link_get (&handles->entries [slot]);
1821 obj = (MonoObject *)handles->entries [slot];
1824 /* print a warning? */
1826 unlock_handles (handles);
1827 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
1832 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
1834 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1835 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1836 HandleData *handles = &gc_handles [type];
1837 MonoObject *old_obj = NULL;
1839 g_assert (type < HANDLE_TYPE_MAX);
1840 lock_handles (handles);
1841 if (slot < handles->size && slot_occupied (handles, slot)) {
1842 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1843 old_obj = (MonoObject *)handles->entries [slot];
1844 if (handles->entries [slot])
1845 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1847 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
1848 /*FIXME, what to use when obj == null?*/
1849 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1851 handles->entries [slot] = obj;
1854 /* print a warning? */
1856 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
1857 unlock_handles (handles);
1861 mono_gc_is_null (void)
1867 * mono_gchandle_is_in_domain:
1868 * \param gchandle a GCHandle's handle.
1869 * \param domain An application domain.
1871 * Use this function to determine if the \p gchandle points to an
1872 * object allocated in the specified \p domain.
1874 * \returns TRUE if the object wrapped by the \p gchandle belongs to the specific \p domain.
1877 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
1879 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1880 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1881 HandleData *handles = &gc_handles [type];
1882 gboolean result = FALSE;
1884 if (type >= HANDLE_TYPE_MAX)
1887 lock_handles (handles);
1888 if (slot < handles->size && slot_occupied (handles, slot)) {
1889 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1890 result = domain->domain_id == handles->domain_ids [slot];
1893 obj = (MonoObject *)handles->entries [slot];
1897 result = domain == mono_object_domain (obj);
1900 /* print a warning? */
1902 unlock_handles (handles);
1907 * mono_gchandle_free:
1908 * \param gchandle a GCHandle's handle.
1910 * Frees the \p gchandle handle. If there are no outstanding
1911 * references, the garbage collector can reclaim the memory of the
1915 mono_gchandle_free (guint32 gchandle)
1917 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1918 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1919 HandleData *handles = &gc_handles [type];
1920 if (type >= HANDLE_TYPE_MAX)
1923 lock_handles (handles);
1924 if (slot < handles->size && slot_occupied (handles, slot)) {
1925 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1926 if (handles->entries [slot])
1927 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1929 handles->entries [slot] = NULL;
1931 vacate_slot (handles, slot);
1933 /* print a warning? */
1935 #ifndef DISABLE_PERFCOUNTERS
1936 mono_perfcounters->gc_num_handles--;
1938 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
1939 unlock_handles (handles);
1940 MONO_PROFILER_RAISE (gc_handle_deleted, (gchandle, handles->type));
1944 * mono_gchandle_free_domain:
1945 * \param domain domain that is unloading
1947 * Function used internally to cleanup any GC handle for objects belonging
1948 * to the specified domain during appdomain unload.
1951 mono_gchandle_free_domain (MonoDomain *domain)
1955 for (type = HANDLE_TYPE_MIN; type < HANDLE_PINNED; ++type) {
1957 HandleData *handles = &gc_handles [type];
1958 lock_handles (handles);
1959 for (slot = 0; slot < handles->size; ++slot) {
1960 if (!slot_occupied (handles, slot))
1962 if (MONO_GC_HANDLE_TYPE_IS_WEAK (type)) {
1963 if (domain->domain_id == handles->domain_ids [slot]) {
1964 vacate_slot (handles, slot);
1965 if (handles->entries [slot])
1966 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1969 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
1970 vacate_slot (handles, slot);
1971 handles->entries [slot] = NULL;
1975 unlock_handles (handles);
1981 MONO_EMPTY_SOURCE_FILE (boehm_gc);
1982 #endif /* no Boehm GC */