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 register_test_toggleref_callback (void);
62 #define BOEHM_GC_BIT_FINALIZER_AWARE 1
63 static MonoGCFinalizerCallbacks fin_callbacks;
67 static mono_mutex_t handle_section;
68 #define lock_handles(handles) mono_os_mutex_lock (&handle_section)
69 #define unlock_handles(handles) mono_os_mutex_unlock (&handle_section)
76 guint slot_hint : 24; /* starting slot for search in bitmap */
77 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
78 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
82 #define EMPTY_HANDLE_DATA(type) {NULL, NULL, 0, (type), 0, NULL}
84 /* weak and weak-track arrays will be allocated in malloc memory
86 static HandleData gc_handles [] = {
87 EMPTY_HANDLE_DATA (HANDLE_WEAK),
88 EMPTY_HANDLE_DATA (HANDLE_WEAK_TRACK),
89 EMPTY_HANDLE_DATA (HANDLE_NORMAL),
90 EMPTY_HANDLE_DATA (HANDLE_PINNED)
94 mono_gc_warning (char *msg, GC_word arg)
96 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_GC, msg, (unsigned long)arg);
99 static void on_gc_notification (GC_EventType event);
100 static void on_gc_heap_resize (size_t new_size);
103 mono_gc_base_init (void)
110 mono_counters_init ();
113 mono_w32handle_init ();
117 * Handle the case when we are called from a thread different from the main thread,
119 * FIXME: Move this to libgc where it belongs.
121 * we used to do this only when running on valgrind,
122 * but it happens also in other setups.
124 #if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
129 pthread_getattr_np (pthread_self (), &attr);
130 pthread_attr_getstack (&attr, &sstart, &size);
131 pthread_attr_destroy (&attr);
132 /*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/
133 /* apparently with some linuxthreads implementations sstart can be NULL,
134 * fallback to the more imprecise method (bug# 78096).
137 GC_stackbottom = (char*)sstart + size;
140 gsize stack_bottom = (gsize)&dummy;
141 stack_bottom += 4095;
142 stack_bottom &= ~4095;
143 GC_stackbottom = (char*)stack_bottom;
146 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
147 GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ());
148 #elif defined(__OpenBSD__)
149 # include <pthread_np.h>
154 rslt = pthread_stackseg_np(pthread_self(), &ss);
155 g_assert (rslt == 0);
157 GC_stackbottom = (char*)ss.ss_sp;
162 gsize stack_bottom = (gsize)&dummy;
163 stack_bottom += 4095;
164 stack_bottom &= ~4095;
165 /*g_print ("stackbottom is: %p\n", (char*)stack_bottom);*/
166 GC_stackbottom = (char*)stack_bottom;
170 #if !defined(PLATFORM_ANDROID)
171 /* If GC_no_dls is set to true, GC_find_limit is not called. This causes a seg fault on Android. */
175 if ((env = g_getenv ("MONO_GC_DEBUG"))) {
176 char **opts = g_strsplit (env, ",", -1);
177 for (char **ptr = opts; ptr && *ptr; ptr ++) {
179 if (!strcmp (opt, "do-not-finalize")) {
180 mono_do_not_finalize = 1;
181 } else if (!strcmp (opt, "log-finalizers")) {
191 GC_set_warn_proc (mono_gc_warning);
192 GC_finalize_on_demand = 1;
193 GC_finalizer_notifier = mono_gc_finalize_notify;
195 GC_init_gcj_malloc (5, NULL);
196 GC_allow_register_threads ();
198 if ((env = g_getenv ("MONO_GC_PARAMS"))) {
199 char **ptr, **opts = g_strsplit (env, ",", -1);
200 for (ptr = opts; *ptr; ++ptr) {
202 if (g_str_has_prefix (opt, "max-heap-size=")) {
205 opt = strchr (opt, '=') + 1;
206 if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap)) {
207 if (max_heap < MIN_BOEHM_MAX_HEAP_SIZE) {
208 fprintf (stderr, "max-heap-size must be at least %dMb.\n", MIN_BOEHM_MAX_HEAP_SIZE_IN_MB);
211 GC_set_max_heap_size (max_heap);
213 fprintf (stderr, "max-heap-size must be an integer.\n");
217 } else if (g_str_has_prefix (opt, "toggleref-test")) {
218 register_test_toggleref_callback ();
221 /* Could be a parameter for sgen */
223 fprintf (stderr, "MONO_GC_PARAMS must be a comma-delimited list of one or more of the following:\n");
224 fprintf (stderr, " max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
233 mono_thread_callbacks_init ();
234 mono_thread_info_init (sizeof (MonoThreadInfo));
235 mono_os_mutex_init (&mono_gc_lock);
236 mono_os_mutex_init_recursive (&handle_section);
238 mono_thread_info_attach ();
240 GC_set_on_collection_event (on_gc_notification);
241 GC_on_heap_resize = on_gc_heap_resize;
243 gc_initialized = TRUE;
247 mono_gc_base_cleanup (void)
249 GC_finalizer_notifier = NULL;
254 * \param generation GC generation identifier
256 * Perform a garbage collection for the given generation, higher numbers
257 * mean usually older objects. Collecting a high-numbered generation
258 * implies collecting also the lower-numbered generations.
259 * The maximum value for \p generation can be retrieved with a call to
260 * \c mono_gc_max_generation, so this function is usually called as:
262 * <code>mono_gc_collect (mono_gc_max_generation ());</code>
265 mono_gc_collect (int generation)
267 #ifndef DISABLE_PERFCOUNTERS
268 mono_perfcounters->gc_induced++;
274 * mono_gc_max_generation:
276 * Get the maximum generation number used by the current garbage
277 * collector. The value will be 0 for the Boehm collector, 1 or more
278 * for the generational collectors.
280 * Returns: the maximum generation number.
283 mono_gc_max_generation (void)
289 * mono_gc_get_generation:
290 * \param object a managed object
292 * Get the garbage collector's generation that \p object belongs to.
293 * Use this has a hint only.
295 * \returns a garbage collector generation number
298 mono_gc_get_generation (MonoObject *object)
304 * mono_gc_collection_count:
305 * \param generation a GC generation number
307 * Get how many times a garbage collection has been performed
308 * for the given \p generation number.
310 * \returns the number of garbage collections
313 mono_gc_collection_count (int generation)
319 * mono_gc_add_memory_pressure:
320 * \param value amount of bytes
322 * Adjust the garbage collector's view of how many bytes of memory
323 * are indirectly referenced by managed objects (for example unmanaged
324 * memory holding image or other binary data).
325 * This is a hint only to the garbage collector algorithm.
326 * Note that negative amounts of p value will decrease the memory
330 mono_gc_add_memory_pressure (gint64 value)
335 * mono_gc_get_used_size:
337 * Get the approximate amount of memory used by managed objects.
339 * Returns: the amount of memory used in bytes
342 mono_gc_get_used_size (void)
344 return GC_get_heap_size () - GC_get_free_bytes ();
348 * mono_gc_get_heap_size:
350 * Get the amount of memory used by the garbage collector.
352 * Returns: the size of the heap in bytes
355 mono_gc_get_heap_size (void)
357 return GC_get_heap_size ();
361 mono_gc_is_gc_thread (void)
363 return GC_thread_is_registered ();
367 mono_gc_thread_attach (MonoThreadInfo* info)
369 struct GC_stack_base sb;
372 /* TODO: use GC_get_stack_base instead of baseptr. */
373 sb.mem_base = info->stack_end;
374 res = GC_register_my_thread (&sb);
375 if (res == GC_UNIMPLEMENTED)
376 return NULL; /* Cannot happen with GC v7+. */
378 info->handle_stack = mono_handle_stack_alloc ();
384 mono_gc_thread_detach_with_lock (MonoThreadInfo *p)
386 MonoNativeThreadId tid;
388 tid = mono_thread_info_get_tid (p);
390 if (p->runtime_thread)
391 mono_threads_add_joinable_thread ((gpointer)tid);
393 mono_handle_stack_free (p->handle_stack);
397 mono_gc_thread_in_critical_region (MonoThreadInfo *info)
403 mono_object_is_alive (MonoObject* o)
405 return GC_is_marked ((ptr_t)o);
409 mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
414 static gint64 gc_start_time;
417 on_gc_notification (GC_EventType event)
419 MonoGCEvent e = (MonoGCEvent)event;
422 case MONO_GC_EVENT_PRE_STOP_WORLD:
423 MONO_GC_WORLD_STOP_BEGIN ();
426 case MONO_GC_EVENT_POST_STOP_WORLD:
427 MONO_GC_WORLD_STOP_END ();
430 case MONO_GC_EVENT_PRE_START_WORLD:
431 MONO_GC_WORLD_RESTART_BEGIN (1);
434 case MONO_GC_EVENT_POST_START_WORLD:
435 MONO_GC_WORLD_RESTART_END (1);
438 case MONO_GC_EVENT_START:
440 #ifndef DISABLE_PERFCOUNTERS
441 if (mono_perfcounters)
442 mono_perfcounters->gc_collections0++;
444 gc_stats.major_gc_count ++;
445 gc_start_time = mono_100ns_ticks ();
448 case MONO_GC_EVENT_END:
450 #if defined(ENABLE_DTRACE) && defined(__sun__)
451 /* This works around a dtrace -G problem on Solaris.
452 Limit its actual use to when the probe is enabled. */
453 if (MONO_GC_END_ENABLED ())
457 #ifndef DISABLE_PERFCOUNTERS
458 if (mono_perfcounters) {
459 guint64 heap_size = GC_get_heap_size ();
460 guint64 used_size = heap_size - GC_get_free_bytes ();
461 mono_perfcounters->gc_total_bytes = used_size;
462 mono_perfcounters->gc_committed_bytes = heap_size;
463 mono_perfcounters->gc_reserved_bytes = heap_size;
464 mono_perfcounters->gc_gen0size = heap_size;
467 gc_stats.major_gc_time += mono_100ns_ticks () - gc_start_time;
468 mono_trace_message (MONO_TRACE_GC, "gc took %d usecs", (mono_100ns_ticks () - gc_start_time) / 10);
474 mono_profiler_gc_event (e, 0);
477 case MONO_GC_EVENT_PRE_STOP_WORLD:
478 mono_thread_info_suspend_lock ();
479 mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0);
481 case MONO_GC_EVENT_POST_START_WORLD:
482 mono_thread_info_suspend_unlock ();
483 mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0);
492 on_gc_heap_resize (size_t new_size)
494 guint64 heap_size = GC_get_heap_size ();
495 #ifndef DISABLE_PERFCOUNTERS
496 if (mono_perfcounters) {
497 mono_perfcounters->gc_committed_bytes = heap_size;
498 mono_perfcounters->gc_reserved_bytes = heap_size;
499 mono_perfcounters->gc_gen0size = heap_size;
502 mono_profiler_gc_heap_resize (new_size);
506 mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg)
508 /* for some strange reason, they want one extra byte on the end */
509 GC_add_roots (start, start + size + 1);
515 mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg)
517 return mono_gc_register_root (start, size, descr, source, msg);
521 mono_gc_deregister_root (char* addr)
524 /* FIXME: libgc doesn't define this work win32 for some reason */
525 /* FIXME: No size info */
526 GC_remove_roots (addr, addr + sizeof (gpointer) + 1);
531 mono_gc_weak_link_add (void **link_addr, MonoObject *obj, gboolean track)
533 /* libgc requires that we use HIDE_POINTER... */
534 *link_addr = (void*)HIDE_POINTER (obj);
536 GC_REGISTER_LONG_LINK (link_addr, obj);
538 GC_GENERAL_REGISTER_DISAPPEARING_LINK (link_addr, obj);
542 mono_gc_weak_link_remove (void **link_addr, gboolean track)
545 GC_unregister_long_link (link_addr);
547 GC_unregister_disappearing_link (link_addr);
552 reveal_link (gpointer link_addr)
554 void **link_a = (void **)link_addr;
555 return REVEAL_POINTER (*link_a);
559 mono_gc_weak_link_get (void **link_addr)
561 MonoObject *obj = (MonoObject *)GC_call_with_alloc_lock (reveal_link, link_addr);
562 if (obj == (MonoObject *) -1)
568 mono_gc_make_descr_for_string (gsize *bitmap, int numbits)
570 return mono_gc_make_descr_from_bitmap (bitmap, numbits);
574 mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
576 return mono_gc_make_descr_from_bitmap (bitmap, numbits);
580 mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size)
582 /* libgc has no usable support for arrays... */
583 return GC_NO_DESCRIPTOR;
587 mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits)
589 /* It seems there are issues when the bitmap doesn't fit: play it safe */
591 return GC_NO_DESCRIPTOR;
593 return (gpointer)GC_make_descriptor ((GC_bitmap)bitmap, numbits);
597 mono_gc_make_vector_descr (void)
603 mono_gc_make_root_descr_all_refs (int numbits)
609 mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, const char *msg)
611 return GC_MALLOC_UNCOLLECTABLE (size);
615 mono_gc_free_fixed (void* addr)
621 mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
625 if (!vtable->klass->has_references) {
626 obj = (MonoObject *)GC_MALLOC_ATOMIC (size);
627 if (G_UNLIKELY (!obj))
630 obj->vtable = vtable;
631 obj->synchronisation = NULL;
633 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
634 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
635 obj = (MonoObject *)GC_GCJ_MALLOC (size, vtable);
636 if (G_UNLIKELY (!obj))
639 obj = (MonoObject *)GC_MALLOC (size);
640 if (G_UNLIKELY (!obj))
643 obj->vtable = vtable;
646 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
647 mono_profiler_allocation (obj);
653 mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
657 if (!vtable->klass->has_references) {
658 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
659 if (G_UNLIKELY (!obj))
662 obj->obj.vtable = vtable;
663 obj->obj.synchronisation = NULL;
665 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
666 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
667 obj = (MonoArray *)GC_GCJ_MALLOC (size, vtable);
668 if (G_UNLIKELY (!obj))
671 obj = (MonoArray *)GC_MALLOC (size);
672 if (G_UNLIKELY (!obj))
675 obj->obj.vtable = vtable;
678 obj->max_length = max_length;
680 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
681 mono_profiler_allocation (&obj->obj);
687 mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uintptr_t bounds_size)
691 if (!vtable->klass->has_references) {
692 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
693 if (G_UNLIKELY (!obj))
696 obj->obj.vtable = vtable;
697 obj->obj.synchronisation = NULL;
699 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
700 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
701 obj = (MonoArray *)GC_GCJ_MALLOC (size, vtable);
702 if (G_UNLIKELY (!obj))
705 obj = (MonoArray *)GC_MALLOC (size);
706 if (G_UNLIKELY (!obj))
709 obj->obj.vtable = vtable;
712 obj->max_length = max_length;
715 obj->bounds = (MonoArrayBounds *) ((char *) obj + size - bounds_size);
717 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
718 mono_profiler_allocation (&obj->obj);
724 mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
726 MonoString *obj = (MonoString *)GC_MALLOC_ATOMIC (size);
727 if (G_UNLIKELY (!obj))
730 obj->object.vtable = vtable;
731 obj->object.synchronisation = NULL;
733 obj->chars [len] = 0;
735 if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
736 mono_profiler_allocation (&obj->object);
742 mono_gc_alloc_mature (MonoVTable *vtable, size_t size)
744 return mono_gc_alloc_obj (vtable, size);
748 mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size)
750 return mono_gc_alloc_obj (vtable, size);
754 mono_gc_invoke_finalizers (void)
756 /* There is a bug in GC_invoke_finalizer () in versions <= 6.2alpha4:
757 * the 'mem_freed' variable is not initialized when there are no
758 * objects to finalize, which leads to strange behavior later on.
759 * The check is necessary to work around that bug.
761 if (GC_should_invoke_finalizers ())
762 return GC_invoke_finalizers ();
767 mono_gc_pending_finalizers (void)
769 return GC_should_invoke_finalizers ();
773 mono_gc_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* value)
775 *(void**)field_ptr = value;
779 mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* value)
781 *(void**)slot_ptr = value;
785 mono_gc_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
787 mono_gc_memmove_aligned (dest_ptr, src_ptr, count * sizeof (gpointer));
791 mono_gc_wbarrier_generic_store (gpointer ptr, MonoObject* value)
793 *(void**)ptr = value;
797 mono_gc_wbarrier_generic_store_atomic (gpointer ptr, MonoObject *value)
799 InterlockedWritePointer ((volatile gpointer *)ptr, value);
803 mono_gc_wbarrier_generic_nostore (gpointer ptr)
808 mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass)
810 mono_gc_memmove_atomic (dest, src, count * mono_class_value_size (klass, NULL));
814 mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
816 /* do not copy the sync state */
817 mono_gc_memmove_aligned ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject),
818 mono_object_class (obj)->instance_size - sizeof (MonoObject));
822 mono_gc_clear_domain (MonoDomain *domain)
827 mono_gc_suspend_finalizers (void)
832 mono_gc_get_suspend_signal (void)
834 return GC_get_suspend_signal ();
838 mono_gc_get_restart_signal (void)
840 return GC_get_thr_restart_signal ();
843 #if defined(USE_COMPILER_TLS) && defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
844 extern __thread void* GC_thread_tls;
845 #include "metadata-internals.h"
851 while (!(v & (1 << i)))
858 ATYPE_FREEPTR_FOR_BOX,
866 create_allocator (int atype, int tls_key, gboolean slowpath)
868 int index_var, bytes_var, my_fl_var, my_entry_var;
869 guint32 no_freelist_branch, not_small_enough_branch = 0;
870 guint32 size_overflow_branch = 0;
871 MonoMethodBuilder *mb;
873 MonoMethodSignature *csig;
874 const char *name = NULL;
877 g_assert_not_reached ();
879 if (atype == ATYPE_FREEPTR) {
880 name = slowpath ? "SlowAllocPtrfree" : "AllocPtrfree";
881 } else if (atype == ATYPE_FREEPTR_FOR_BOX) {
882 name = slowpath ? "SlowAllocPtrfreeBox" : "AllocPtrfreeBox";
883 } else if (atype == ATYPE_NORMAL) {
884 name = slowpath ? "SlowAlloc" : "Alloc";
885 } else if (atype == ATYPE_GCJ) {
886 name = slowpath ? "SlowAllocGcj" : "AllocGcj";
887 } else if (atype == ATYPE_STRING) {
888 name = slowpath ? "SlowAllocString" : "AllocString";
890 g_assert_not_reached ();
893 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
895 if (atype == ATYPE_STRING) {
896 csig->ret = &mono_defaults.string_class->byval_arg;
897 csig->params [0] = &mono_defaults.int_class->byval_arg;
898 csig->params [1] = &mono_defaults.int32_class->byval_arg;
900 csig->ret = &mono_defaults.object_class->byval_arg;
901 csig->params [0] = &mono_defaults.int_class->byval_arg;
902 csig->params [1] = &mono_defaults.int32_class->byval_arg;
905 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ALLOC);
908 goto always_slowpath;
910 bytes_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
911 if (atype == ATYPE_STRING) {
912 /* a string alloator method takes the args: (vtable, len) */
913 /* bytes = (offsetof (MonoString, chars) + ((len + 1) * 2)); */
914 mono_mb_emit_ldarg (mb, 1);
915 mono_mb_emit_icon (mb, 1);
916 mono_mb_emit_byte (mb, MONO_CEE_ADD);
917 mono_mb_emit_icon (mb, 1);
918 mono_mb_emit_byte (mb, MONO_CEE_SHL);
919 // sizeof (MonoString) might include padding
920 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoString, chars));
921 mono_mb_emit_byte (mb, MONO_CEE_ADD);
922 mono_mb_emit_stloc (mb, bytes_var);
924 mono_mb_emit_ldarg (mb, 1);
925 mono_mb_emit_stloc (mb, bytes_var);
928 /* this is needed for strings/arrays only as the other big types are never allocated with this method */
929 if (atype == ATYPE_STRING) {
931 /* if (!SMALL_ENOUGH (bytes)) jump slow_path;*/
932 mono_mb_emit_ldloc (mb, bytes_var);
933 mono_mb_emit_icon (mb, (NFREELISTS-1) * GRANULARITY);
934 not_small_enough_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BGT_UN_S);
935 /* check for overflow */
936 mono_mb_emit_ldloc (mb, bytes_var);
937 mono_mb_emit_icon (mb, sizeof (MonoString));
938 size_overflow_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLE_UN_S);
941 /* int index = INDEX_FROM_BYTES(bytes); */
942 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
944 mono_mb_emit_ldloc (mb, bytes_var);
945 mono_mb_emit_icon (mb, GRANULARITY - 1);
946 mono_mb_emit_byte (mb, MONO_CEE_ADD);
947 mono_mb_emit_icon (mb, shift_amount (GRANULARITY));
948 mono_mb_emit_byte (mb, MONO_CEE_SHR_UN);
949 mono_mb_emit_icon (mb, shift_amount (sizeof (gpointer)));
950 mono_mb_emit_byte (mb, MONO_CEE_SHL);
951 /* index var is already adjusted into bytes */
952 mono_mb_emit_stloc (mb, index_var);
954 my_fl_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
955 my_entry_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
956 /* my_fl = ((GC_thread)tsd) -> ptrfree_freelists + index; */
957 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
958 mono_mb_emit_byte (mb, 0x0D); /* CEE_MONO_TLS */
959 mono_mb_emit_i4 (mb, tls_key);
960 if (atype == ATYPE_FREEPTR || atype == ATYPE_FREEPTR_FOR_BOX || atype == ATYPE_STRING)
961 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
962 + G_STRUCT_OFFSET (struct thread_local_freelists,
964 else if (atype == ATYPE_NORMAL)
965 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
966 + G_STRUCT_OFFSET (struct thread_local_freelists,
968 else if (atype == ATYPE_GCJ)
969 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
970 + G_STRUCT_OFFSET (struct thread_local_freelists,
973 g_assert_not_reached ();
974 mono_mb_emit_byte (mb, MONO_CEE_ADD);
975 mono_mb_emit_ldloc (mb, index_var);
976 mono_mb_emit_byte (mb, MONO_CEE_ADD);
977 mono_mb_emit_stloc (mb, my_fl_var);
979 /* my_entry = *my_fl; */
980 mono_mb_emit_ldloc (mb, my_fl_var);
981 mono_mb_emit_byte (mb, MONO_CEE_LDIND_I);
982 mono_mb_emit_stloc (mb, my_entry_var);
984 /* if (EXPECT((word)my_entry >= HBLKSIZE, 1)) { */
985 mono_mb_emit_ldloc (mb, my_entry_var);
986 mono_mb_emit_icon (mb, HBLKSIZE);
987 no_freelist_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLT_UN_S);
989 /* ptr_t next = obj_link(my_entry); *my_fl = next; */
990 mono_mb_emit_ldloc (mb, my_fl_var);
991 mono_mb_emit_ldloc (mb, my_entry_var);
992 mono_mb_emit_byte (mb, MONO_CEE_LDIND_I);
993 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
995 /* set the vtable and clear the words in the object */
996 mono_mb_emit_ldloc (mb, my_entry_var);
997 mono_mb_emit_ldarg (mb, 0);
998 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1000 if (atype == ATYPE_FREEPTR) {
1001 int start_var, end_var, start_loop;
1002 /* end = my_entry + bytes; start = my_entry + sizeof (gpointer);
1004 start_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1005 end_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1006 mono_mb_emit_ldloc (mb, my_entry_var);
1007 mono_mb_emit_ldloc (mb, bytes_var);
1008 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1009 mono_mb_emit_stloc (mb, end_var);
1010 mono_mb_emit_ldloc (mb, my_entry_var);
1011 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoObject, synchronisation));
1012 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1013 mono_mb_emit_stloc (mb, start_var);
1017 * } while (start < end);
1019 start_loop = mono_mb_get_label (mb);
1020 mono_mb_emit_ldloc (mb, start_var);
1021 mono_mb_emit_icon (mb, 0);
1022 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1023 mono_mb_emit_ldloc (mb, start_var);
1024 mono_mb_emit_icon (mb, sizeof (gpointer));
1025 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1026 mono_mb_emit_stloc (mb, start_var);
1028 mono_mb_emit_ldloc (mb, start_var);
1029 mono_mb_emit_ldloc (mb, end_var);
1030 mono_mb_emit_byte (mb, MONO_CEE_BLT_UN_S);
1031 mono_mb_emit_byte (mb, start_loop - (mono_mb_get_label (mb) + 1));
1032 } else if (atype == ATYPE_FREEPTR_FOR_BOX || atype == ATYPE_STRING) {
1033 /* need to clear just the sync pointer */
1034 mono_mb_emit_ldloc (mb, my_entry_var);
1035 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoObject, synchronisation));
1036 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1037 mono_mb_emit_icon (mb, 0);
1038 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1041 if (atype == ATYPE_STRING) {
1042 /* need to set length and clear the last char */
1043 /* s->length = len; */
1044 mono_mb_emit_ldloc (mb, my_entry_var);
1045 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoString, length));
1046 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1047 mono_mb_emit_ldarg (mb, 1);
1048 mono_mb_emit_byte (mb, MONO_CEE_STIND_I4);
1049 /* s->chars [len] = 0; */
1050 mono_mb_emit_ldloc (mb, my_entry_var);
1051 mono_mb_emit_ldloc (mb, bytes_var);
1052 mono_mb_emit_icon (mb, 2);
1053 mono_mb_emit_byte (mb, MONO_CEE_SUB);
1054 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1055 mono_mb_emit_icon (mb, 0);
1056 mono_mb_emit_byte (mb, MONO_CEE_STIND_I2);
1059 /* return my_entry; */
1060 mono_mb_emit_ldloc (mb, my_entry_var);
1061 mono_mb_emit_byte (mb, MONO_CEE_RET);
1063 mono_mb_patch_short_branch (mb, no_freelist_branch);
1064 if (not_small_enough_branch > 0)
1065 mono_mb_patch_short_branch (mb, not_small_enough_branch);
1066 if (size_overflow_branch > 0)
1067 mono_mb_patch_short_branch (mb, size_overflow_branch);
1069 /* the slow path: we just call back into the runtime */
1071 if (atype == ATYPE_STRING) {
1072 mono_mb_emit_ldarg (mb, 1);
1073 mono_mb_emit_icall (mb, ves_icall_string_alloc);
1075 mono_mb_emit_ldarg (mb, 0);
1076 mono_mb_emit_icall (mb, ves_icall_object_new_specific);
1079 mono_mb_emit_byte (mb, MONO_CEE_RET);
1081 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1082 info->d.alloc.gc_name = "boehm";
1083 info->d.alloc.alloc_type = atype;
1084 mb->init_locals = FALSE;
1086 res = mono_mb_create (mb, csig, 8, info);
1092 static MonoMethod* alloc_method_cache [ATYPE_NUM];
1093 static MonoMethod* slowpath_alloc_method_cache [ATYPE_NUM];
1096 mono_gc_is_critical_method (MonoMethod *method)
1100 for (i = 0; i < ATYPE_NUM; ++i)
1101 if (method == alloc_method_cache [i] || method == slowpath_alloc_method_cache [i])
1108 * If possible, generate a managed method that can quickly allocate objects in class
1109 * @klass. The method will typically have an thread-local inline allocation sequence.
1110 * The signature of the called method is:
1111 * object allocate (MonoVTable *vtable)
1112 * Some of the logic here is similar to mono_class_get_allocation_ftn () i object.c,
1114 * The thread local alloc logic is taken from libgc/pthread_support.c.
1118 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1123 * Tls implementation changed, we jump to tls native getters/setters.
1124 * Is boehm managed allocator ok with this ? Do we even care ?
1128 if (!SMALL_ENOUGH (klass->instance_size))
1130 if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass))
1132 if (mono_profiler_get_events () & (MONO_PROFILE_ALLOCATIONS | MONO_PROFILE_STATISTICAL))
1136 if (mono_class_is_open_constructed_type (&klass->byval_arg))
1138 if (klass->byval_arg.type == MONO_TYPE_STRING) {
1139 atype = ATYPE_STRING;
1140 } else if (!known_instance_size) {
1142 } else if (!klass->has_references) {
1144 atype = ATYPE_FREEPTR_FOR_BOX;
1146 atype = ATYPE_FREEPTR;
1150 * disabled because we currently do a runtime choice anyway, to
1151 * deal with multiple appdomains.
1152 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1155 atype = ATYPE_NORMAL;
1158 return mono_gc_get_managed_allocator_by_type (atype, MANAGED_ALLOCATOR_REGULAR);
1162 mono_gc_get_managed_array_allocator (MonoClass *klass)
1168 * mono_gc_get_managed_allocator_by_type:
1170 * Return a managed allocator method corresponding to allocator type ATYPE.
1173 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1176 gboolean slowpath = variant != MANAGED_ALLOCATOR_REGULAR;
1177 MonoMethod **cache = slowpath ? slowpath_alloc_method_cache : alloc_method_cache;
1181 res = cache [atype];
1185 res = create_allocator (atype, -1, slowpath);
1186 mono_os_mutex_lock (&mono_gc_lock);
1187 if (cache [atype]) {
1188 mono_free_method (res);
1189 res = cache [atype];
1191 mono_memory_barrier ();
1192 cache [atype] = res;
1194 mono_os_mutex_unlock (&mono_gc_lock);
1199 mono_gc_get_managed_allocator_types (void)
1205 mono_gc_get_write_barrier (void)
1207 g_assert_not_reached ();
1214 mono_gc_is_critical_method (MonoMethod *method)
1220 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1226 mono_gc_get_managed_array_allocator (MonoClass *klass)
1232 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1238 mono_gc_get_managed_allocator_types (void)
1244 mono_gc_get_write_barrier (void)
1246 g_assert_not_reached ();
1253 mono_gc_get_specific_write_barrier (gboolean is_concurrent)
1255 g_assert_not_reached ();
1260 mono_gc_get_aligned_size_for_allocator (int size)
1266 mono_gc_get_gc_name (void)
1272 mono_gc_invoke_with_gc_lock (MonoGCLockedCallbackFunc func, void *data)
1274 return GC_call_with_alloc_lock (func, data);
1278 mono_gc_get_description (void)
1280 return g_strdup (DEFAULT_GC_NAME);
1284 mono_gc_set_desktop_mode (void)
1290 mono_gc_is_moving (void)
1296 mono_gc_is_disabled (void)
1298 if (GC_dont_gc || g_hasenv ("GC_DONT_GC"))
1305 mono_gc_wbarrier_range_copy (gpointer _dest, gpointer _src, int size)
1307 g_assert_not_reached ();
1311 mono_gc_get_range_copy_func (void)
1313 return &mono_gc_wbarrier_range_copy;
1317 mono_gc_get_card_table (int *shift_bits, gpointer *card_mask)
1319 g_assert_not_reached ();
1324 mono_gc_card_table_nursery_check (void)
1326 g_assert_not_reached ();
1331 mono_gc_get_nursery (int *shift_bits, size_t *size)
1337 mono_gc_precise_stack_mark_enabled (void)
1343 mono_gc_get_logfile (void)
1349 mono_gc_params_set (const char* options)
1354 mono_gc_debug_set (const char* options)
1359 mono_gc_conservatively_scan_area (void *start, void *end)
1361 g_assert_not_reached ();
1365 mono_gc_scan_object (void *obj, void *gc_data)
1367 g_assert_not_reached ();
1372 mono_gc_get_bitmap_for_descr (void *descr, int *numbits)
1374 g_assert_not_reached ();
1379 mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks)
1384 mono_gc_set_stack_end (void *stack_end)
1388 void mono_gc_set_skip_thread (gboolean value)
1393 mono_gc_register_for_finalization (MonoObject *obj, void *user_data)
1398 /* This assertion is not valid when GC_DEBUG is defined */
1399 g_assert (GC_base (obj) == (char*)obj - offset);
1402 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, (GC_finalization_proc)user_data, GUINT_TO_POINTER (offset), NULL, NULL);
1407 mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
1409 /* it is being replaced by GC_pthread_create on some
1410 * platforms, see libgc/include/gc_pthread_redirects.h */
1411 return pthread_create (new_thread, attr, start_routine, arg);
1416 BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reserved)
1418 return GC_DllMain (module_handle, reason, reserved);
1423 mono_gc_get_vtable_bits (MonoClass *klass)
1425 if (fin_callbacks.is_class_finalization_aware) {
1426 if (fin_callbacks.is_class_finalization_aware (klass))
1427 return BOEHM_GC_BIT_FINALIZER_AWARE;
1433 * mono_gc_register_altstack:
1435 * Register the dimensions of the normal stack and altstack with the collector.
1436 * Currently, STACK/STACK_SIZE is only used when the thread is suspended while it is on an altstack.
1439 mono_gc_register_altstack (gpointer stack, gint32 stack_size, gpointer altstack, gint32 altstack_size)
1441 GC_register_altstack (stack, stack_size, altstack, altstack_size);
1445 mono_gc_get_los_limit (void)
1451 mono_gc_set_string_length (MonoString *str, gint32 new_length)
1453 mono_unichar2 *new_end = str->chars + new_length;
1455 /* zero the discarded string. This null-delimits the string and allows
1456 * the space to be reclaimed by SGen. */
1458 memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
1459 str->length = new_length;
1463 mono_gc_user_markers_supported (void)
1469 mono_gc_make_root_descr_user (MonoGCRootMarkFunc marker)
1471 g_assert_not_reached ();
1475 /* Toggleref support */
1478 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
1480 if (GC_toggleref_add ((GC_PTR)object, (int)strong_ref) != GC_SUCCESS)
1481 g_error ("GC_toggleref_add failed\n");
1485 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
1487 GC_set_toggleref_func ((GC_ToggleRefStatus (*) (GC_PTR obj)) proccess_toggleref);
1490 /* Test support code */
1492 static MonoToggleRefStatus
1493 test_toggleref_callback (MonoObject *obj)
1495 static MonoClassField *mono_toggleref_test_field;
1496 MonoToggleRefStatus status = MONO_TOGGLE_REF_DROP;
1498 if (!mono_toggleref_test_field) {
1499 mono_toggleref_test_field = mono_class_get_field_from_name (mono_object_get_class (obj), "__test");
1500 g_assert (mono_toggleref_test_field);
1503 mono_field_get_value (obj, mono_toggleref_test_field, &status);
1504 printf ("toggleref-cb obj %d\n", status);
1509 register_test_toggleref_callback (void)
1511 mono_gc_toggleref_register_callback (test_toggleref_callback);
1515 is_finalization_aware (MonoObject *obj)
1517 MonoVTable *vt = obj->vtable;
1518 return (vt->gc_bits & BOEHM_GC_BIT_FINALIZER_AWARE) == BOEHM_GC_BIT_FINALIZER_AWARE;
1522 fin_notifier (MonoObject *obj)
1524 if (is_finalization_aware (obj))
1525 fin_callbacks.object_queued_for_finalization (obj);
1529 mono_gc_register_finalizer_callbacks (MonoGCFinalizerCallbacks *callbacks)
1531 if (callbacks->version != MONO_GC_FINALIZER_EXTENSION_VERSION)
1532 g_error ("Invalid finalizer callback version. Expected %d but got %d\n", MONO_GC_FINALIZER_EXTENSION_VERSION, callbacks->version);
1534 fin_callbacks = *callbacks;
1536 GC_set_await_finalize_proc ((void (*) (GC_PTR))fin_notifier);
1539 #define BITMAP_SIZE (sizeof (*((HandleData *)NULL)->bitmap) * CHAR_BIT)
1541 static inline gboolean
1542 slot_occupied (HandleData *handles, guint slot) {
1543 return handles->bitmap [slot / BITMAP_SIZE] & (1 << (slot % BITMAP_SIZE));
1547 vacate_slot (HandleData *handles, guint slot) {
1548 handles->bitmap [slot / BITMAP_SIZE] &= ~(1 << (slot % BITMAP_SIZE));
1552 occupy_slot (HandleData *handles, guint slot) {
1553 handles->bitmap [slot / BITMAP_SIZE] |= 1 << (slot % BITMAP_SIZE);
1557 find_first_unset (guint32 bitmap)
1560 for (i = 0; i < 32; ++i) {
1561 if (!(bitmap & (1 << i)))
1568 handle_data_alloc_entries (HandleData *handles)
1571 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1572 handles->entries = (void **)g_malloc0 (sizeof (*handles->entries) * handles->size);
1573 handles->domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * handles->size);
1575 handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1577 handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT);
1581 handle_data_next_unset (HandleData *handles)
1584 for (slot = handles->slot_hint; slot < handles->size / BITMAP_SIZE; ++slot) {
1585 if (handles->bitmap [slot] == 0xffffffff)
1587 handles->slot_hint = slot;
1588 return find_first_unset (handles->bitmap [slot]);
1594 handle_data_first_unset (HandleData *handles)
1597 for (slot = 0; slot < handles->slot_hint; ++slot) {
1598 if (handles->bitmap [slot] == 0xffffffff)
1600 handles->slot_hint = slot;
1601 return find_first_unset (handles->bitmap [slot]);
1606 /* Returns the index of the current slot in the bitmap. */
1608 handle_data_grow (HandleData *handles, gboolean track)
1610 guint32 *new_bitmap;
1611 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
1613 /* resize and copy the bitmap */
1614 new_bitmap = (guint32 *)g_malloc0 (new_size / CHAR_BIT);
1615 memcpy (new_bitmap, handles->bitmap, handles->size / CHAR_BIT);
1616 g_free (handles->bitmap);
1617 handles->bitmap = new_bitmap;
1619 /* resize and copy the entries */
1620 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1622 guint16 *domain_ids;
1624 domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * new_size);
1625 entries = (void **)g_malloc0 (sizeof (*handles->entries) * new_size);
1626 memcpy (domain_ids, handles->domain_ids, sizeof (*handles->domain_ids) * handles->size);
1627 for (i = 0; i < handles->size; ++i) {
1628 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
1630 mono_gc_weak_link_add (&(entries [i]), obj, track);
1631 mono_gc_weak_link_remove (&(handles->entries [i]), track);
1633 g_assert (!handles->entries [i]);
1636 g_free (handles->entries);
1637 g_free (handles->domain_ids);
1638 handles->entries = entries;
1639 handles->domain_ids = domain_ids;
1642 entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1643 mono_gc_memmove_aligned (entries, handles->entries, sizeof (*handles->entries) * handles->size);
1644 mono_gc_free_fixed (handles->entries);
1645 handles->entries = entries;
1647 handles->slot_hint = handles->size / BITMAP_SIZE;
1648 handles->size = new_size;
1652 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
1656 lock_handles (handles);
1658 handle_data_alloc_entries (handles);
1659 i = handle_data_next_unset (handles);
1660 if (i == -1 && handles->slot_hint != 0)
1661 i = handle_data_first_unset (handles);
1663 handle_data_grow (handles, track);
1666 slot = handles->slot_hint * BITMAP_SIZE + i;
1667 occupy_slot (handles, slot);
1668 handles->entries [slot] = NULL;
1669 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1670 /*FIXME, what to use when obj == null?*/
1671 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1673 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
1675 handles->entries [slot] = obj;
1678 #ifndef DISABLE_PERFCOUNTERS
1679 mono_perfcounters->gc_num_handles++;
1681 unlock_handles (handles);
1682 res = MONO_GC_HANDLE (slot, handles->type);
1683 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
1688 * mono_gchandle_new:
1689 * \param obj managed object to get a handle for
1690 * \param pinned whether the object should be pinned
1692 * This returns a handle that wraps the object, this is used to keep a
1693 * reference to a managed object from the unmanaged world and preventing the
1694 * object from being disposed.
1696 * If \p pinned is false the address of the object can not be obtained, if it is
1697 * true the address of the object can be obtained. This will also pin the
1698 * object so it will not be possible by a moving garbage collector to move the
1701 * \returns a handle that can be used to access the object from
1705 mono_gchandle_new (MonoObject *obj, gboolean pinned)
1707 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
1711 * mono_gchandle_new_weakref:
1712 * \param obj managed object to get a handle for
1713 * \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.
1715 * This returns a weak handle that wraps the object, this is used to
1716 * keep a reference to a managed object from the unmanaged world.
1717 * Unlike the \c mono_gchandle_new the object can be reclaimed by the
1718 * garbage collector. In this case the value of the GCHandle will be
1721 * If \p track_resurrection is TRUE the object will be tracked through
1722 * finalization and if the object is resurrected during the execution
1723 * of the finalizer, then the returned weakref will continue to hold
1724 * a reference to the object. If \p track_resurrection is FALSE, then
1725 * the weak reference's target will become NULL as soon as the object
1726 * is passed on to the finalizer.
1728 * \returns a handle that can be used to access the object from
1732 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
1734 return alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
1738 * mono_gchandle_get_target:
1739 * \param gchandle a GCHandle's handle.
1741 * The handle was previously created by calling \c mono_gchandle_new or
1742 * \c mono_gchandle_new_weakref.
1744 * \returns A pointer to the \c MonoObject* represented by the handle or
1745 * NULL for a collected object if using a weakref handle.
1748 mono_gchandle_get_target (guint32 gchandle)
1750 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1751 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1752 HandleData *handles = &gc_handles [type];
1753 MonoObject *obj = NULL;
1754 if (type >= HANDLE_TYPE_MAX)
1757 lock_handles (handles);
1758 if (slot < handles->size && slot_occupied (handles, slot)) {
1759 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1760 obj = mono_gc_weak_link_get (&handles->entries [slot]);
1762 obj = (MonoObject *)handles->entries [slot];
1765 /* print a warning? */
1767 unlock_handles (handles);
1768 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
1773 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
1775 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1776 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1777 HandleData *handles = &gc_handles [type];
1778 MonoObject *old_obj = NULL;
1780 g_assert (type < HANDLE_TYPE_MAX);
1781 lock_handles (handles);
1782 if (slot < handles->size && slot_occupied (handles, slot)) {
1783 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1784 old_obj = (MonoObject *)handles->entries [slot];
1785 if (handles->entries [slot])
1786 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1788 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
1789 /*FIXME, what to use when obj == null?*/
1790 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1792 handles->entries [slot] = obj;
1795 /* print a warning? */
1797 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
1798 unlock_handles (handles);
1802 mono_gc_is_null (void)
1808 * mono_gchandle_is_in_domain:
1809 * \param gchandle a GCHandle's handle.
1810 * \param domain An application domain.
1812 * Use this function to determine if the \p gchandle points to an
1813 * object allocated in the specified \p domain.
1815 * \returns TRUE if the object wrapped by the \p gchandle belongs to the specific \p domain.
1818 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
1820 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1821 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1822 HandleData *handles = &gc_handles [type];
1823 gboolean result = FALSE;
1825 if (type >= HANDLE_TYPE_MAX)
1828 lock_handles (handles);
1829 if (slot < handles->size && slot_occupied (handles, slot)) {
1830 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1831 result = domain->domain_id == handles->domain_ids [slot];
1834 obj = (MonoObject *)handles->entries [slot];
1838 result = domain == mono_object_domain (obj);
1841 /* print a warning? */
1843 unlock_handles (handles);
1848 * mono_gchandle_free:
1849 * \param gchandle a GCHandle's handle.
1851 * Frees the \p gchandle handle. If there are no outstanding
1852 * references, the garbage collector can reclaim the memory of the
1856 mono_gchandle_free (guint32 gchandle)
1858 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1859 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1860 HandleData *handles = &gc_handles [type];
1861 if (type >= HANDLE_TYPE_MAX)
1864 lock_handles (handles);
1865 if (slot < handles->size && slot_occupied (handles, slot)) {
1866 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1867 if (handles->entries [slot])
1868 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1870 handles->entries [slot] = NULL;
1872 vacate_slot (handles, slot);
1874 /* print a warning? */
1876 #ifndef DISABLE_PERFCOUNTERS
1877 mono_perfcounters->gc_num_handles--;
1879 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
1880 unlock_handles (handles);
1881 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
1885 * mono_gchandle_free_domain:
1886 * \param domain domain that is unloading
1888 * Function used internally to cleanup any GC handle for objects belonging
1889 * to the specified domain during appdomain unload.
1892 mono_gchandle_free_domain (MonoDomain *domain)
1896 for (type = HANDLE_TYPE_MIN; type < HANDLE_PINNED; ++type) {
1898 HandleData *handles = &gc_handles [type];
1899 lock_handles (handles);
1900 for (slot = 0; slot < handles->size; ++slot) {
1901 if (!slot_occupied (handles, slot))
1903 if (MONO_GC_HANDLE_TYPE_IS_WEAK (type)) {
1904 if (domain->domain_id == handles->domain_ids [slot]) {
1905 vacate_slot (handles, slot);
1906 if (handles->entries [slot])
1907 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1910 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
1911 vacate_slot (handles, slot);
1912 handles->entries [slot] = NULL;
1916 unlock_handles (handles);
1922 MONO_EMPTY_SOURCE_FILE (boehm_gc);
1923 #endif /* no Boehm GC */