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_register (MonoThreadInfo* info, void *baseptr);
62 boehm_thread_unregister (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;
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) && !defined(__native_client__)
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);*/
143 * The calculation above doesn't seem to work on ia64, also we need to set
144 * GC_register_stackbottom as well, but don't know how.
147 /* apparently with some linuxthreads implementations sstart can be NULL,
148 * fallback to the more imprecise method (bug# 78096).
151 GC_stackbottom = (char*)sstart + size;
154 gsize stack_bottom = (gsize)&dummy;
155 stack_bottom += 4095;
156 stack_bottom &= ~4095;
157 GC_stackbottom = (char*)stack_bottom;
161 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
162 GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ());
163 #elif defined(__OpenBSD__)
164 # include <pthread_np.h>
169 rslt = pthread_stackseg_np(pthread_self(), &ss);
170 g_assert (rslt == 0);
172 GC_stackbottom = (char*)ss.ss_sp;
174 #elif defined(__native_client__)
175 /* Do nothing, GC_stackbottom is set correctly in libgc */
179 gsize stack_bottom = (gsize)&dummy;
180 stack_bottom += 4095;
181 stack_bottom &= ~4095;
182 /*g_print ("stackbottom is: %p\n", (char*)stack_bottom);*/
183 GC_stackbottom = (char*)stack_bottom;
187 #if !defined(PLATFORM_ANDROID)
188 /* If GC_no_dls is set to true, GC_find_limit is not called. This causes a seg fault on Android. */
192 if ((env = g_getenv ("MONO_GC_DEBUG"))) {
193 char **opts = g_strsplit (env, ",", -1);
194 for (char **ptr = opts; ptr && *ptr; ptr ++) {
196 if (!strcmp (opt, "do-not-finalize")) {
197 mono_do_not_finalize = 1;
198 } else if (!strcmp (opt, "log-finalizers")) {
208 GC_set_warn_proc (mono_gc_warning);
209 GC_finalize_on_demand = 1;
210 GC_finalizer_notifier = mono_gc_finalize_notify;
212 GC_init_gcj_malloc (5, NULL);
213 GC_allow_register_threads ();
215 if ((env = g_getenv ("MONO_GC_PARAMS"))) {
216 char **ptr, **opts = g_strsplit (env, ",", -1);
217 for (ptr = opts; *ptr; ++ptr) {
219 if (g_str_has_prefix (opt, "max-heap-size=")) {
222 opt = strchr (opt, '=') + 1;
223 if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap)) {
224 if (max_heap < MIN_BOEHM_MAX_HEAP_SIZE) {
225 fprintf (stderr, "max-heap-size must be at least %dMb.\n", MIN_BOEHM_MAX_HEAP_SIZE_IN_MB);
228 GC_set_max_heap_size (max_heap);
230 fprintf (stderr, "max-heap-size must be an integer.\n");
234 } else if (g_str_has_prefix (opt, "toggleref-test")) {
235 register_test_toggleref_callback ();
238 /* Could be a parameter for sgen */
240 fprintf (stderr, "MONO_GC_PARAMS must be a comma-delimited list of one or more of the following:\n");
241 fprintf (stderr, " max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
250 memset (&cb, 0, sizeof (cb));
251 cb.thread_register = boehm_thread_register;
252 cb.thread_unregister = boehm_thread_unregister;
253 cb.thread_detach = boehm_thread_detach;
254 cb.mono_method_is_critical = (gboolean (*)(void *))mono_runtime_is_critical_method;
256 mono_threads_init (&cb, sizeof (MonoThreadInfo));
257 mono_os_mutex_init (&mono_gc_lock);
258 mono_os_mutex_init_recursive (&handle_section);
260 mono_thread_info_attach (&dummy);
262 GC_set_on_collection_event (on_gc_notification);
263 GC_on_heap_resize = on_gc_heap_resize;
265 gc_initialized = TRUE;
269 mono_gc_base_cleanup (void)
271 GC_finalizer_notifier = NULL;
276 * \param generation GC generation identifier
278 * Perform a garbage collection for the given generation, higher numbers
279 * mean usually older objects. Collecting a high-numbered generation
280 * implies collecting also the lower-numbered generations.
281 * The maximum value for \p generation can be retrieved with a call to
282 * \c mono_gc_max_generation, so this function is usually called as:
284 * <code>mono_gc_collect (mono_gc_max_generation ());</code>
287 mono_gc_collect (int generation)
289 #ifndef DISABLE_PERFCOUNTERS
290 mono_perfcounters->gc_induced++;
296 * mono_gc_max_generation:
298 * Get the maximum generation number used by the current garbage
299 * collector. The value will be 0 for the Boehm collector, 1 or more
300 * for the generational collectors.
302 * Returns: the maximum generation number.
305 mono_gc_max_generation (void)
311 * mono_gc_get_generation:
312 * \param object a managed object
314 * Get the garbage collector's generation that \p object belongs to.
315 * Use this has a hint only.
317 * \returns a garbage collector generation number
320 mono_gc_get_generation (MonoObject *object)
326 * mono_gc_collection_count:
327 * \param generation a GC generation number
329 * Get how many times a garbage collection has been performed
330 * for the given \p generation number.
332 * \returns the number of garbage collections
335 mono_gc_collection_count (int generation)
341 * mono_gc_add_memory_pressure:
342 * \param value amount of bytes
344 * Adjust the garbage collector's view of how many bytes of memory
345 * are indirectly referenced by managed objects (for example unmanaged
346 * memory holding image or other binary data).
347 * This is a hint only to the garbage collector algorithm.
348 * Note that negative amounts of p value will decrease the memory
352 mono_gc_add_memory_pressure (gint64 value)
357 * mono_gc_get_used_size:
359 * Get the approximate amount of memory used by managed objects.
361 * Returns: the amount of memory used in bytes
364 mono_gc_get_used_size (void)
366 return GC_get_heap_size () - GC_get_free_bytes ();
370 * mono_gc_get_heap_size:
372 * Get the amount of memory used by the garbage collector.
374 * Returns: the size of the heap in bytes
377 mono_gc_get_heap_size (void)
379 return GC_get_heap_size ();
383 mono_gc_is_gc_thread (void)
385 return GC_thread_is_registered ();
389 mono_gc_register_thread (void *baseptr)
391 return mono_thread_info_attach (baseptr) != NULL;
395 boehm_thread_register (MonoThreadInfo* info, void *baseptr)
397 struct GC_stack_base sb;
400 /* TODO: use GC_get_stack_base instead of baseptr. */
401 sb.mem_base = baseptr;
402 res = GC_register_my_thread (&sb);
403 if (res == GC_UNIMPLEMENTED)
404 return NULL; /* Cannot happen with GC v7+. */
406 info->handle_stack = mono_handle_stack_alloc ();
412 boehm_thread_unregister (MonoThreadInfo *p)
414 MonoNativeThreadId tid;
416 tid = mono_thread_info_get_tid (p);
418 if (p->runtime_thread)
419 mono_threads_add_joinable_thread ((gpointer)tid);
423 boehm_thread_detach (MonoThreadInfo *p)
425 if (mono_thread_internal_current_is_attached ())
426 mono_thread_detach_internal (mono_thread_internal_current ());
430 mono_object_is_alive (MonoObject* o)
432 return GC_is_marked ((ptr_t)o);
436 mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
441 static gint64 gc_start_time;
444 on_gc_notification (GC_EventType event)
446 MonoGCEvent e = (MonoGCEvent)event;
449 case MONO_GC_EVENT_PRE_STOP_WORLD:
450 MONO_GC_WORLD_STOP_BEGIN ();
453 case MONO_GC_EVENT_POST_STOP_WORLD:
454 MONO_GC_WORLD_STOP_END ();
457 case MONO_GC_EVENT_PRE_START_WORLD:
458 MONO_GC_WORLD_RESTART_BEGIN (1);
461 case MONO_GC_EVENT_POST_START_WORLD:
462 MONO_GC_WORLD_RESTART_END (1);
465 case MONO_GC_EVENT_START:
467 #ifndef DISABLE_PERFCOUNTERS
468 if (mono_perfcounters)
469 mono_perfcounters->gc_collections0++;
471 gc_stats.major_gc_count ++;
472 gc_start_time = mono_100ns_ticks ();
475 case MONO_GC_EVENT_END:
477 #if defined(ENABLE_DTRACE) && defined(__sun__)
478 /* This works around a dtrace -G problem on Solaris.
479 Limit its actual use to when the probe is enabled. */
480 if (MONO_GC_END_ENABLED ())
484 #ifndef DISABLE_PERFCOUNTERS
485 if (mono_perfcounters) {
486 guint64 heap_size = GC_get_heap_size ();
487 guint64 used_size = heap_size - GC_get_free_bytes ();
488 mono_perfcounters->gc_total_bytes = used_size;
489 mono_perfcounters->gc_committed_bytes = heap_size;
490 mono_perfcounters->gc_reserved_bytes = heap_size;
491 mono_perfcounters->gc_gen0size = heap_size;
494 gc_stats.major_gc_time += mono_100ns_ticks () - gc_start_time;
495 mono_trace_message (MONO_TRACE_GC, "gc took %d usecs", (mono_100ns_ticks () - gc_start_time) / 10);
501 mono_profiler_gc_event (e, 0);
504 case MONO_GC_EVENT_PRE_STOP_WORLD:
505 mono_thread_info_suspend_lock ();
506 mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0);
508 case MONO_GC_EVENT_POST_START_WORLD:
509 mono_thread_info_suspend_unlock ();
510 mono_profiler_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;
529 mono_profiler_gc_heap_resize (new_size);
533 mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg)
535 /* for some strange reason, they want one extra byte on the end */
536 GC_add_roots (start, start + size + 1);
542 mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg)
544 return mono_gc_register_root (start, size, descr, source, msg);
548 mono_gc_deregister_root (char* addr)
551 /* FIXME: libgc doesn't define this work win32 for some reason */
552 /* FIXME: No size info */
553 GC_remove_roots (addr, addr + sizeof (gpointer) + 1);
558 mono_gc_weak_link_add (void **link_addr, MonoObject *obj, gboolean track)
560 /* libgc requires that we use HIDE_POINTER... */
561 *link_addr = (void*)HIDE_POINTER (obj);
563 GC_REGISTER_LONG_LINK (link_addr, obj);
565 GC_GENERAL_REGISTER_DISAPPEARING_LINK (link_addr, obj);
569 mono_gc_weak_link_remove (void **link_addr, gboolean track)
572 GC_unregister_long_link (link_addr);
574 GC_unregister_disappearing_link (link_addr);
579 reveal_link (gpointer link_addr)
581 void **link_a = (void **)link_addr;
582 return REVEAL_POINTER (*link_a);
586 mono_gc_weak_link_get (void **link_addr)
588 MonoObject *obj = (MonoObject *)GC_call_with_alloc_lock (reveal_link, link_addr);
589 if (obj == (MonoObject *) -1)
595 mono_gc_make_descr_for_string (gsize *bitmap, int numbits)
597 return mono_gc_make_descr_from_bitmap (bitmap, numbits);
601 mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
603 return mono_gc_make_descr_from_bitmap (bitmap, numbits);
607 mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size)
609 /* libgc has no usable support for arrays... */
610 return GC_NO_DESCRIPTOR;
614 mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits)
616 /* It seems there are issues when the bitmap doesn't fit: play it safe */
618 return GC_NO_DESCRIPTOR;
620 return (gpointer)GC_make_descriptor ((GC_bitmap)bitmap, numbits);
624 mono_gc_make_vector_descr (void)
630 mono_gc_make_root_descr_all_refs (int numbits)
636 mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, const char *msg)
638 return GC_MALLOC_UNCOLLECTABLE (size);
642 mono_gc_free_fixed (void* addr)
648 mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
652 if (!vtable->klass->has_references) {
653 obj = (MonoObject *)GC_MALLOC_ATOMIC (size);
654 if (G_UNLIKELY (!obj))
657 obj->vtable = vtable;
658 obj->synchronisation = NULL;
660 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
661 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
662 obj = (MonoObject *)GC_GCJ_MALLOC (size, vtable);
663 if (G_UNLIKELY (!obj))
666 obj = (MonoObject *)GC_MALLOC (size);
667 if (G_UNLIKELY (!obj))
670 obj->vtable = vtable;
673 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
674 mono_profiler_allocation (obj);
680 mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
684 if (!vtable->klass->has_references) {
685 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
686 if (G_UNLIKELY (!obj))
689 obj->obj.vtable = vtable;
690 obj->obj.synchronisation = NULL;
692 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
693 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
694 obj = (MonoArray *)GC_GCJ_MALLOC (size, vtable);
695 if (G_UNLIKELY (!obj))
698 obj = (MonoArray *)GC_MALLOC (size);
699 if (G_UNLIKELY (!obj))
702 obj->obj.vtable = vtable;
705 obj->max_length = max_length;
707 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
708 mono_profiler_allocation (&obj->obj);
714 mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uintptr_t bounds_size)
718 if (!vtable->klass->has_references) {
719 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
720 if (G_UNLIKELY (!obj))
723 obj->obj.vtable = vtable;
724 obj->obj.synchronisation = NULL;
726 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
727 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
728 obj = (MonoArray *)GC_GCJ_MALLOC (size, vtable);
729 if (G_UNLIKELY (!obj))
732 obj = (MonoArray *)GC_MALLOC (size);
733 if (G_UNLIKELY (!obj))
736 obj->obj.vtable = vtable;
739 obj->max_length = max_length;
742 obj->bounds = (MonoArrayBounds *) ((char *) obj + size - bounds_size);
744 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
745 mono_profiler_allocation (&obj->obj);
751 mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
753 MonoString *obj = (MonoString *)GC_MALLOC_ATOMIC (size);
754 if (G_UNLIKELY (!obj))
757 obj->object.vtable = vtable;
758 obj->object.synchronisation = NULL;
760 obj->chars [len] = 0;
762 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
763 mono_profiler_allocation (&obj->object);
769 mono_gc_alloc_mature (MonoVTable *vtable, size_t size)
771 return mono_gc_alloc_obj (vtable, size);
775 mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size)
777 return mono_gc_alloc_obj (vtable, size);
781 mono_gc_invoke_finalizers (void)
783 /* There is a bug in GC_invoke_finalizer () in versions <= 6.2alpha4:
784 * the 'mem_freed' variable is not initialized when there are no
785 * objects to finalize, which leads to strange behavior later on.
786 * The check is necessary to work around that bug.
788 if (GC_should_invoke_finalizers ())
789 return GC_invoke_finalizers ();
794 mono_gc_pending_finalizers (void)
796 return GC_should_invoke_finalizers ();
800 mono_gc_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* value)
802 *(void**)field_ptr = value;
806 mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* value)
808 *(void**)slot_ptr = value;
812 mono_gc_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
814 mono_gc_memmove_aligned (dest_ptr, src_ptr, count * sizeof (gpointer));
818 mono_gc_wbarrier_generic_store (gpointer ptr, MonoObject* value)
820 *(void**)ptr = value;
824 mono_gc_wbarrier_generic_store_atomic (gpointer ptr, MonoObject *value)
826 InterlockedWritePointer ((volatile gpointer *)ptr, value);
830 mono_gc_wbarrier_generic_nostore (gpointer ptr)
835 mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass)
837 mono_gc_memmove_atomic (dest, src, count * mono_class_value_size (klass, NULL));
841 mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
843 /* do not copy the sync state */
844 mono_gc_memmove_aligned ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject),
845 mono_object_class (obj)->instance_size - sizeof (MonoObject));
849 mono_gc_clear_domain (MonoDomain *domain)
854 mono_gc_suspend_finalizers (void)
859 mono_gc_get_suspend_signal (void)
861 return GC_get_suspend_signal ();
865 mono_gc_get_restart_signal (void)
867 return GC_get_thr_restart_signal ();
870 #if defined(USE_COMPILER_TLS) && defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
871 extern __thread void* GC_thread_tls;
872 #include "metadata-internals.h"
878 while (!(v & (1 << i)))
885 ATYPE_FREEPTR_FOR_BOX,
893 create_allocator (int atype, int tls_key, gboolean slowpath)
895 int index_var, bytes_var, my_fl_var, my_entry_var;
896 guint32 no_freelist_branch, not_small_enough_branch = 0;
897 guint32 size_overflow_branch = 0;
898 MonoMethodBuilder *mb;
900 MonoMethodSignature *csig;
901 const char *name = NULL;
904 g_assert_not_reached ();
906 if (atype == ATYPE_FREEPTR) {
907 name = slowpath ? "SlowAllocPtrfree" : "AllocPtrfree";
908 } else if (atype == ATYPE_FREEPTR_FOR_BOX) {
909 name = slowpath ? "SlowAllocPtrfreeBox" : "AllocPtrfreeBox";
910 } else if (atype == ATYPE_NORMAL) {
911 name = slowpath ? "SlowAlloc" : "Alloc";
912 } else if (atype == ATYPE_GCJ) {
913 name = slowpath ? "SlowAllocGcj" : "AllocGcj";
914 } else if (atype == ATYPE_STRING) {
915 name = slowpath ? "SlowAllocString" : "AllocString";
917 g_assert_not_reached ();
920 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
922 if (atype == ATYPE_STRING) {
923 csig->ret = &mono_defaults.string_class->byval_arg;
924 csig->params [0] = &mono_defaults.int_class->byval_arg;
925 csig->params [1] = &mono_defaults.int32_class->byval_arg;
927 csig->ret = &mono_defaults.object_class->byval_arg;
928 csig->params [0] = &mono_defaults.int_class->byval_arg;
929 csig->params [1] = &mono_defaults.int32_class->byval_arg;
932 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ALLOC);
935 goto always_slowpath;
937 bytes_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
938 if (atype == ATYPE_STRING) {
939 /* a string alloator method takes the args: (vtable, len) */
940 /* bytes = (offsetof (MonoString, chars) + ((len + 1) * 2)); */
941 mono_mb_emit_ldarg (mb, 1);
942 mono_mb_emit_icon (mb, 1);
943 mono_mb_emit_byte (mb, MONO_CEE_ADD);
944 mono_mb_emit_icon (mb, 1);
945 mono_mb_emit_byte (mb, MONO_CEE_SHL);
946 // sizeof (MonoString) might include padding
947 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoString, chars));
948 mono_mb_emit_byte (mb, MONO_CEE_ADD);
949 mono_mb_emit_stloc (mb, bytes_var);
951 mono_mb_emit_ldarg (mb, 1);
952 mono_mb_emit_stloc (mb, bytes_var);
955 /* this is needed for strings/arrays only as the other big types are never allocated with this method */
956 if (atype == ATYPE_STRING) {
958 /* if (!SMALL_ENOUGH (bytes)) jump slow_path;*/
959 mono_mb_emit_ldloc (mb, bytes_var);
960 mono_mb_emit_icon (mb, (NFREELISTS-1) * GRANULARITY);
961 not_small_enough_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BGT_UN_S);
962 /* check for overflow */
963 mono_mb_emit_ldloc (mb, bytes_var);
964 mono_mb_emit_icon (mb, sizeof (MonoString));
965 size_overflow_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLE_UN_S);
968 /* int index = INDEX_FROM_BYTES(bytes); */
969 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
971 mono_mb_emit_ldloc (mb, bytes_var);
972 mono_mb_emit_icon (mb, GRANULARITY - 1);
973 mono_mb_emit_byte (mb, MONO_CEE_ADD);
974 mono_mb_emit_icon (mb, shift_amount (GRANULARITY));
975 mono_mb_emit_byte (mb, MONO_CEE_SHR_UN);
976 mono_mb_emit_icon (mb, shift_amount (sizeof (gpointer)));
977 mono_mb_emit_byte (mb, MONO_CEE_SHL);
978 /* index var is already adjusted into bytes */
979 mono_mb_emit_stloc (mb, index_var);
981 my_fl_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
982 my_entry_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
983 /* my_fl = ((GC_thread)tsd) -> ptrfree_freelists + index; */
984 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
985 mono_mb_emit_byte (mb, 0x0D); /* CEE_MONO_TLS */
986 mono_mb_emit_i4 (mb, tls_key);
987 if (atype == ATYPE_FREEPTR || atype == ATYPE_FREEPTR_FOR_BOX || atype == ATYPE_STRING)
988 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
989 + G_STRUCT_OFFSET (struct thread_local_freelists,
991 else if (atype == ATYPE_NORMAL)
992 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
993 + G_STRUCT_OFFSET (struct thread_local_freelists,
995 else if (atype == ATYPE_GCJ)
996 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
997 + G_STRUCT_OFFSET (struct thread_local_freelists,
1000 g_assert_not_reached ();
1001 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1002 mono_mb_emit_ldloc (mb, index_var);
1003 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1004 mono_mb_emit_stloc (mb, my_fl_var);
1006 /* my_entry = *my_fl; */
1007 mono_mb_emit_ldloc (mb, my_fl_var);
1008 mono_mb_emit_byte (mb, MONO_CEE_LDIND_I);
1009 mono_mb_emit_stloc (mb, my_entry_var);
1011 /* if (EXPECT((word)my_entry >= HBLKSIZE, 1)) { */
1012 mono_mb_emit_ldloc (mb, my_entry_var);
1013 mono_mb_emit_icon (mb, HBLKSIZE);
1014 no_freelist_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLT_UN_S);
1016 /* ptr_t next = obj_link(my_entry); *my_fl = next; */
1017 mono_mb_emit_ldloc (mb, my_fl_var);
1018 mono_mb_emit_ldloc (mb, my_entry_var);
1019 mono_mb_emit_byte (mb, MONO_CEE_LDIND_I);
1020 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1022 /* set the vtable and clear the words in the object */
1023 mono_mb_emit_ldloc (mb, my_entry_var);
1024 mono_mb_emit_ldarg (mb, 0);
1025 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1027 if (atype == ATYPE_FREEPTR) {
1028 int start_var, end_var, start_loop;
1029 /* end = my_entry + bytes; start = my_entry + sizeof (gpointer);
1031 start_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1032 end_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1033 mono_mb_emit_ldloc (mb, my_entry_var);
1034 mono_mb_emit_ldloc (mb, bytes_var);
1035 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1036 mono_mb_emit_stloc (mb, end_var);
1037 mono_mb_emit_ldloc (mb, my_entry_var);
1038 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoObject, synchronisation));
1039 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1040 mono_mb_emit_stloc (mb, start_var);
1044 * } while (start < end);
1046 start_loop = mono_mb_get_label (mb);
1047 mono_mb_emit_ldloc (mb, start_var);
1048 mono_mb_emit_icon (mb, 0);
1049 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1050 mono_mb_emit_ldloc (mb, start_var);
1051 mono_mb_emit_icon (mb, sizeof (gpointer));
1052 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1053 mono_mb_emit_stloc (mb, start_var);
1055 mono_mb_emit_ldloc (mb, start_var);
1056 mono_mb_emit_ldloc (mb, end_var);
1057 mono_mb_emit_byte (mb, MONO_CEE_BLT_UN_S);
1058 mono_mb_emit_byte (mb, start_loop - (mono_mb_get_label (mb) + 1));
1059 } else if (atype == ATYPE_FREEPTR_FOR_BOX || atype == ATYPE_STRING) {
1060 /* need to clear just the sync pointer */
1061 mono_mb_emit_ldloc (mb, my_entry_var);
1062 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoObject, synchronisation));
1063 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1064 mono_mb_emit_icon (mb, 0);
1065 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1068 if (atype == ATYPE_STRING) {
1069 /* need to set length and clear the last char */
1070 /* s->length = len; */
1071 mono_mb_emit_ldloc (mb, my_entry_var);
1072 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoString, length));
1073 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1074 mono_mb_emit_ldarg (mb, 1);
1075 mono_mb_emit_byte (mb, MONO_CEE_STIND_I4);
1076 /* s->chars [len] = 0; */
1077 mono_mb_emit_ldloc (mb, my_entry_var);
1078 mono_mb_emit_ldloc (mb, bytes_var);
1079 mono_mb_emit_icon (mb, 2);
1080 mono_mb_emit_byte (mb, MONO_CEE_SUB);
1081 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1082 mono_mb_emit_icon (mb, 0);
1083 mono_mb_emit_byte (mb, MONO_CEE_STIND_I2);
1086 /* return my_entry; */
1087 mono_mb_emit_ldloc (mb, my_entry_var);
1088 mono_mb_emit_byte (mb, MONO_CEE_RET);
1090 mono_mb_patch_short_branch (mb, no_freelist_branch);
1091 if (not_small_enough_branch > 0)
1092 mono_mb_patch_short_branch (mb, not_small_enough_branch);
1093 if (size_overflow_branch > 0)
1094 mono_mb_patch_short_branch (mb, size_overflow_branch);
1096 /* the slow path: we just call back into the runtime */
1098 if (atype == ATYPE_STRING) {
1099 mono_mb_emit_ldarg (mb, 1);
1100 mono_mb_emit_icall (mb, ves_icall_string_alloc);
1102 mono_mb_emit_ldarg (mb, 0);
1103 mono_mb_emit_icall (mb, ves_icall_object_new_specific);
1106 mono_mb_emit_byte (mb, MONO_CEE_RET);
1108 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1109 info->d.alloc.gc_name = "boehm";
1110 info->d.alloc.alloc_type = atype;
1111 mb->init_locals = FALSE;
1113 res = mono_mb_create (mb, csig, 8, info);
1119 static MonoMethod* alloc_method_cache [ATYPE_NUM];
1120 static MonoMethod* slowpath_alloc_method_cache [ATYPE_NUM];
1123 mono_gc_is_critical_method (MonoMethod *method)
1127 for (i = 0; i < ATYPE_NUM; ++i)
1128 if (method == alloc_method_cache [i] || method == slowpath_alloc_method_cache [i])
1135 * If possible, generate a managed method that can quickly allocate objects in class
1136 * @klass. The method will typically have an thread-local inline allocation sequence.
1137 * The signature of the called method is:
1138 * object allocate (MonoVTable *vtable)
1139 * Some of the logic here is similar to mono_class_get_allocation_ftn () i object.c,
1141 * The thread local alloc logic is taken from libgc/pthread_support.c.
1145 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1150 * Tls implementation changed, we jump to tls native getters/setters.
1151 * Is boehm managed allocator ok with this ? Do we even care ?
1155 if (!SMALL_ENOUGH (klass->instance_size))
1157 if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass))
1159 if (mono_profiler_get_events () & (MONO_PROFILE_ALLOCATIONS | MONO_PROFILE_STATISTICAL))
1163 if (mono_class_is_open_constructed_type (&klass->byval_arg))
1165 if (klass->byval_arg.type == MONO_TYPE_STRING) {
1166 atype = ATYPE_STRING;
1167 } else if (!known_instance_size) {
1169 } else if (!klass->has_references) {
1171 atype = ATYPE_FREEPTR_FOR_BOX;
1173 atype = ATYPE_FREEPTR;
1177 * disabled because we currently do a runtime choice anyway, to
1178 * deal with multiple appdomains.
1179 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1182 atype = ATYPE_NORMAL;
1185 return mono_gc_get_managed_allocator_by_type (atype, MANAGED_ALLOCATOR_REGULAR);
1189 mono_gc_get_managed_array_allocator (MonoClass *klass)
1195 * mono_gc_get_managed_allocator_by_type:
1197 * Return a managed allocator method corresponding to allocator type ATYPE.
1200 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1203 gboolean slowpath = variant != MANAGED_ALLOCATOR_REGULAR;
1204 MonoMethod **cache = slowpath ? slowpath_alloc_method_cache : alloc_method_cache;
1208 res = cache [atype];
1212 res = create_allocator (atype, -1, slowpath);
1213 mono_os_mutex_lock (&mono_gc_lock);
1214 if (cache [atype]) {
1215 mono_free_method (res);
1216 res = cache [atype];
1218 mono_memory_barrier ();
1219 cache [atype] = res;
1221 mono_os_mutex_unlock (&mono_gc_lock);
1226 mono_gc_get_managed_allocator_types (void)
1232 mono_gc_get_write_barrier (void)
1234 g_assert_not_reached ();
1241 mono_gc_is_critical_method (MonoMethod *method)
1247 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1253 mono_gc_get_managed_array_allocator (MonoClass *klass)
1259 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1265 mono_gc_get_managed_allocator_types (void)
1271 mono_gc_get_write_barrier (void)
1273 g_assert_not_reached ();
1280 mono_gc_get_specific_write_barrier (gboolean is_concurrent)
1282 g_assert_not_reached ();
1287 mono_gc_get_aligned_size_for_allocator (int size)
1293 mono_gc_get_gc_name (void)
1299 mono_gc_invoke_with_gc_lock (MonoGCLockedCallbackFunc func, void *data)
1301 return GC_call_with_alloc_lock (func, data);
1305 mono_gc_get_description (void)
1307 return g_strdup (DEFAULT_GC_NAME);
1311 mono_gc_set_desktop_mode (void)
1317 mono_gc_is_moving (void)
1323 mono_gc_is_disabled (void)
1325 if (GC_dont_gc || g_hasenv ("GC_DONT_GC"))
1332 mono_gc_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, unsigned bitmap)
1334 g_assert_not_reached ();
1339 mono_gc_get_card_table (int *shift_bits, gpointer *card_mask)
1341 g_assert_not_reached ();
1346 mono_gc_card_table_nursery_check (void)
1348 g_assert_not_reached ();
1353 mono_gc_get_nursery (int *shift_bits, size_t *size)
1359 mono_gc_precise_stack_mark_enabled (void)
1365 mono_gc_get_logfile (void)
1371 mono_gc_params_set (const char* options)
1376 mono_gc_debug_set (const char* options)
1381 mono_gc_conservatively_scan_area (void *start, void *end)
1383 g_assert_not_reached ();
1387 mono_gc_scan_object (void *obj, void *gc_data)
1389 g_assert_not_reached ();
1394 mono_gc_get_bitmap_for_descr (void *descr, int *numbits)
1396 g_assert_not_reached ();
1401 mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks)
1406 mono_gc_set_stack_end (void *stack_end)
1410 void mono_gc_set_skip_thread (gboolean value)
1415 mono_gc_register_for_finalization (MonoObject *obj, void *user_data)
1420 /* This assertion is not valid when GC_DEBUG is defined */
1421 g_assert (GC_base (obj) == (char*)obj - offset);
1424 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, (GC_finalization_proc)user_data, GUINT_TO_POINTER (offset), NULL, NULL);
1429 mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
1431 /* it is being replaced by GC_pthread_create on some
1432 * platforms, see libgc/include/gc_pthread_redirects.h */
1433 return pthread_create (new_thread, attr, start_routine, arg);
1438 BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reserved)
1440 return GC_DllMain (module_handle, reason, reserved);
1445 mono_gc_get_vtable_bits (MonoClass *klass)
1447 if (fin_callbacks.is_class_finalization_aware) {
1448 if (fin_callbacks.is_class_finalization_aware (klass))
1449 return BOEHM_GC_BIT_FINALIZER_AWARE;
1455 * mono_gc_register_altstack:
1457 * Register the dimensions of the normal stack and altstack with the collector.
1458 * Currently, STACK/STACK_SIZE is only used when the thread is suspended while it is on an altstack.
1461 mono_gc_register_altstack (gpointer stack, gint32 stack_size, gpointer altstack, gint32 altstack_size)
1463 GC_register_altstack (stack, stack_size, altstack, altstack_size);
1467 mono_gc_get_los_limit (void)
1473 mono_gc_set_string_length (MonoString *str, gint32 new_length)
1475 mono_unichar2 *new_end = str->chars + new_length;
1477 /* zero the discarded string. This null-delimits the string and allows
1478 * the space to be reclaimed by SGen. */
1480 memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
1481 str->length = new_length;
1485 mono_gc_user_markers_supported (void)
1491 mono_gc_make_root_descr_user (MonoGCRootMarkFunc marker)
1493 g_assert_not_reached ();
1497 /* Toggleref support */
1500 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
1502 if (GC_toggleref_add ((GC_PTR)object, (int)strong_ref) != GC_SUCCESS)
1503 g_error ("GC_toggleref_add failed\n");
1507 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
1509 GC_set_toggleref_func ((GC_ToggleRefStatus (*) (GC_PTR obj)) proccess_toggleref);
1512 /* Test support code */
1514 static MonoToggleRefStatus
1515 test_toggleref_callback (MonoObject *obj)
1517 static MonoClassField *mono_toggleref_test_field;
1518 MonoToggleRefStatus status = MONO_TOGGLE_REF_DROP;
1520 if (!mono_toggleref_test_field) {
1521 mono_toggleref_test_field = mono_class_get_field_from_name (mono_object_get_class (obj), "__test");
1522 g_assert (mono_toggleref_test_field);
1525 mono_field_get_value (obj, mono_toggleref_test_field, &status);
1526 printf ("toggleref-cb obj %d\n", status);
1531 register_test_toggleref_callback (void)
1533 mono_gc_toggleref_register_callback (test_toggleref_callback);
1537 is_finalization_aware (MonoObject *obj)
1539 MonoVTable *vt = obj->vtable;
1540 return (vt->gc_bits & BOEHM_GC_BIT_FINALIZER_AWARE) == BOEHM_GC_BIT_FINALIZER_AWARE;
1544 fin_notifier (MonoObject *obj)
1546 if (is_finalization_aware (obj))
1547 fin_callbacks.object_queued_for_finalization (obj);
1551 mono_gc_register_finalizer_callbacks (MonoGCFinalizerCallbacks *callbacks)
1553 if (callbacks->version != MONO_GC_FINALIZER_EXTENSION_VERSION)
1554 g_error ("Invalid finalizer callback version. Expected %d but got %d\n", MONO_GC_FINALIZER_EXTENSION_VERSION, callbacks->version);
1556 fin_callbacks = *callbacks;
1558 GC_set_await_finalize_proc ((void (*) (GC_PTR))fin_notifier);
1561 #define BITMAP_SIZE (sizeof (*((HandleData *)NULL)->bitmap) * CHAR_BIT)
1563 static inline gboolean
1564 slot_occupied (HandleData *handles, guint slot) {
1565 return handles->bitmap [slot / BITMAP_SIZE] & (1 << (slot % BITMAP_SIZE));
1569 vacate_slot (HandleData *handles, guint slot) {
1570 handles->bitmap [slot / BITMAP_SIZE] &= ~(1 << (slot % BITMAP_SIZE));
1574 occupy_slot (HandleData *handles, guint slot) {
1575 handles->bitmap [slot / BITMAP_SIZE] |= 1 << (slot % BITMAP_SIZE);
1579 find_first_unset (guint32 bitmap)
1582 for (i = 0; i < 32; ++i) {
1583 if (!(bitmap & (1 << i)))
1590 handle_data_alloc_entries (HandleData *handles)
1593 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1594 handles->entries = (void **)g_malloc0 (sizeof (*handles->entries) * handles->size);
1595 handles->domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * handles->size);
1597 handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1599 handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT);
1603 handle_data_next_unset (HandleData *handles)
1606 for (slot = handles->slot_hint; slot < handles->size / BITMAP_SIZE; ++slot) {
1607 if (handles->bitmap [slot] == 0xffffffff)
1609 handles->slot_hint = slot;
1610 return find_first_unset (handles->bitmap [slot]);
1616 handle_data_first_unset (HandleData *handles)
1619 for (slot = 0; slot < handles->slot_hint; ++slot) {
1620 if (handles->bitmap [slot] == 0xffffffff)
1622 handles->slot_hint = slot;
1623 return find_first_unset (handles->bitmap [slot]);
1628 /* Returns the index of the current slot in the bitmap. */
1630 handle_data_grow (HandleData *handles, gboolean track)
1632 guint32 *new_bitmap;
1633 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
1635 /* resize and copy the bitmap */
1636 new_bitmap = (guint32 *)g_malloc0 (new_size / CHAR_BIT);
1637 memcpy (new_bitmap, handles->bitmap, handles->size / CHAR_BIT);
1638 g_free (handles->bitmap);
1639 handles->bitmap = new_bitmap;
1641 /* resize and copy the entries */
1642 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1644 guint16 *domain_ids;
1646 domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * new_size);
1647 entries = (void **)g_malloc0 (sizeof (*handles->entries) * new_size);
1648 memcpy (domain_ids, handles->domain_ids, sizeof (*handles->domain_ids) * handles->size);
1649 for (i = 0; i < handles->size; ++i) {
1650 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
1652 mono_gc_weak_link_add (&(entries [i]), obj, track);
1653 mono_gc_weak_link_remove (&(handles->entries [i]), track);
1655 g_assert (!handles->entries [i]);
1658 g_free (handles->entries);
1659 g_free (handles->domain_ids);
1660 handles->entries = entries;
1661 handles->domain_ids = domain_ids;
1664 entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1665 mono_gc_memmove_aligned (entries, handles->entries, sizeof (*handles->entries) * handles->size);
1666 mono_gc_free_fixed (handles->entries);
1667 handles->entries = entries;
1669 handles->slot_hint = handles->size / BITMAP_SIZE;
1670 handles->size = new_size;
1674 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
1678 lock_handles (handles);
1680 handle_data_alloc_entries (handles);
1681 i = handle_data_next_unset (handles);
1682 if (i == -1 && handles->slot_hint != 0)
1683 i = handle_data_first_unset (handles);
1685 handle_data_grow (handles, track);
1688 slot = handles->slot_hint * BITMAP_SIZE + i;
1689 occupy_slot (handles, slot);
1690 handles->entries [slot] = NULL;
1691 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1692 /*FIXME, what to use when obj == null?*/
1693 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1695 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
1697 handles->entries [slot] = obj;
1700 #ifndef DISABLE_PERFCOUNTERS
1701 mono_perfcounters->gc_num_handles++;
1703 unlock_handles (handles);
1704 res = MONO_GC_HANDLE (slot, handles->type);
1705 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
1710 * mono_gchandle_new:
1711 * \param obj managed object to get a handle for
1712 * \param pinned whether the object should be pinned
1714 * This returns a handle that wraps the object, this is used to keep a
1715 * reference to a managed object from the unmanaged world and preventing the
1716 * object from being disposed.
1718 * If \p pinned is false the address of the object can not be obtained, if it is
1719 * true the address of the object can be obtained. This will also pin the
1720 * object so it will not be possible by a moving garbage collector to move the
1723 * \returns a handle that can be used to access the object from
1727 mono_gchandle_new (MonoObject *obj, gboolean pinned)
1729 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
1733 * mono_gchandle_new_weakref:
1734 * \param obj managed object to get a handle for
1735 * \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.
1737 * This returns a weak handle that wraps the object, this is used to
1738 * keep a reference to a managed object from the unmanaged world.
1739 * Unlike the \c mono_gchandle_new the object can be reclaimed by the
1740 * garbage collector. In this case the value of the GCHandle will be
1743 * If \p track_resurrection is TRUE the object will be tracked through
1744 * finalization and if the object is resurrected during the execution
1745 * of the finalizer, then the returned weakref will continue to hold
1746 * a reference to the object. If \p track_resurrection is FALSE, then
1747 * the weak reference's target will become NULL as soon as the object
1748 * is passed on to the finalizer.
1750 * \returns a handle that can be used to access the object from
1754 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
1756 return alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
1760 * mono_gchandle_get_target:
1761 * \param gchandle a GCHandle's handle.
1763 * The handle was previously created by calling \c mono_gchandle_new or
1764 * \c mono_gchandle_new_weakref.
1766 * \returns A pointer to the \c MonoObject* represented by the handle or
1767 * NULL for a collected object if using a weakref handle.
1770 mono_gchandle_get_target (guint32 gchandle)
1772 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1773 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1774 HandleData *handles = &gc_handles [type];
1775 MonoObject *obj = NULL;
1776 if (type >= HANDLE_TYPE_MAX)
1779 lock_handles (handles);
1780 if (slot < handles->size && slot_occupied (handles, slot)) {
1781 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1782 obj = mono_gc_weak_link_get (&handles->entries [slot]);
1784 obj = (MonoObject *)handles->entries [slot];
1787 /* print a warning? */
1789 unlock_handles (handles);
1790 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
1795 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
1797 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1798 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1799 HandleData *handles = &gc_handles [type];
1800 MonoObject *old_obj = NULL;
1802 g_assert (type < HANDLE_TYPE_MAX);
1803 lock_handles (handles);
1804 if (slot < handles->size && slot_occupied (handles, slot)) {
1805 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1806 old_obj = (MonoObject *)handles->entries [slot];
1807 if (handles->entries [slot])
1808 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1810 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
1811 /*FIXME, what to use when obj == null?*/
1812 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1814 handles->entries [slot] = obj;
1817 /* print a warning? */
1819 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
1820 unlock_handles (handles);
1824 mono_gc_is_null (void)
1830 * mono_gchandle_is_in_domain:
1831 * \param gchandle a GCHandle's handle.
1832 * \param domain An application domain.
1834 * Use this function to determine if the \p gchandle points to an
1835 * object allocated in the specified \p domain.
1837 * \returns TRUE if the object wrapped by the \p gchandle belongs to the specific \p domain.
1840 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
1842 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1843 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1844 HandleData *handles = &gc_handles [type];
1845 gboolean result = FALSE;
1847 if (type >= HANDLE_TYPE_MAX)
1850 lock_handles (handles);
1851 if (slot < handles->size && slot_occupied (handles, slot)) {
1852 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1853 result = domain->domain_id == handles->domain_ids [slot];
1856 obj = (MonoObject *)handles->entries [slot];
1860 result = domain == mono_object_domain (obj);
1863 /* print a warning? */
1865 unlock_handles (handles);
1870 * mono_gchandle_free:
1871 * \param gchandle a GCHandle's handle.
1873 * Frees the \p gchandle handle. If there are no outstanding
1874 * references, the garbage collector can reclaim the memory of the
1878 mono_gchandle_free (guint32 gchandle)
1880 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1881 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1882 HandleData *handles = &gc_handles [type];
1883 if (type >= HANDLE_TYPE_MAX)
1886 lock_handles (handles);
1887 if (slot < handles->size && slot_occupied (handles, slot)) {
1888 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1889 if (handles->entries [slot])
1890 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1892 handles->entries [slot] = NULL;
1894 vacate_slot (handles, slot);
1896 /* print a warning? */
1898 #ifndef DISABLE_PERFCOUNTERS
1899 mono_perfcounters->gc_num_handles--;
1901 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
1902 unlock_handles (handles);
1903 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
1907 * mono_gchandle_free_domain:
1908 * \param domain domain that is unloading
1910 * Function used internally to cleanup any GC handle for objects belonging
1911 * to the specified domain during appdomain unload.
1914 mono_gchandle_free_domain (MonoDomain *domain)
1918 for (type = HANDLE_TYPE_MIN; type < HANDLE_PINNED; ++type) {
1920 HandleData *handles = &gc_handles [type];
1921 lock_handles (handles);
1922 for (slot = 0; slot < handles->size; ++slot) {
1923 if (!slot_occupied (handles, slot))
1925 if (MONO_GC_HANDLE_TYPE_IS_WEAK (type)) {
1926 if (domain->domain_id == handles->domain_ids [slot]) {
1927 vacate_slot (handles, slot);
1928 if (handles->entries [slot])
1929 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1932 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
1933 vacate_slot (handles, slot);
1934 handles->entries [slot] = NULL;
1938 unlock_handles (handles);
1944 MONO_EMPTY_SOURCE_FILE (boehm_gc);
1945 #endif /* no Boehm GC */