Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / metadata / boehm-gc.c
index dcfd310f6490ebdd894c863b32e8c65d6ff52f6d..482a7425d030caa2a41fde1ec756c1aa187c35ee 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * boehm-gc.c: GC implementation using either the installed or included Boehm GC.
+/**
+ * \file
+ * GC implementation using either the installed or included Boehm GC.
  *
  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
  * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
@@ -35,6 +36,7 @@
 #include <mono/utils/mono-os-mutex.h>
 #include <mono/utils/mono-counters.h>
 #include <mono/utils/mono-compiler.h>
+#include <mono/utils/unlocked.h>
 
 #if HAVE_BOEHM_GC
 
@@ -43,7 +45,7 @@
 #define THREAD_LOCAL_ALLOC 1
 #include "private/pthread_support.h"
 
-#if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
+#if defined(HOST_DARWIN) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
 void *pthread_get_stackaddr_np(pthread_t);
 #endif
 
@@ -55,12 +57,14 @@ void *pthread_get_stackaddr_np(pthread_t);
 static gboolean gc_initialized = FALSE;
 static mono_mutex_t mono_gc_lock;
 
-static void*
-boehm_thread_register (MonoThreadInfo* info, void *baseptr);
-static void
-boehm_thread_unregister (MonoThreadInfo *p);
+typedef void (*GC_push_other_roots_proc)(void);
+
+static GC_push_other_roots_proc default_push_other_roots;
+static GHashTable *roots;
+
 static void
-boehm_thread_detach (MonoThreadInfo *p);
+mono_push_other_roots(void);
+
 static void
 register_test_toggleref_callback (void);
 
@@ -107,9 +111,7 @@ static void on_gc_heap_resize (size_t new_size);
 void
 mono_gc_base_init (void)
 {
-       MonoThreadInfoCallbacks cb;
-       const char *env;
-       int dummy;
+       char *env;
 
        if (gc_initialized)
                return;
@@ -128,7 +130,7 @@ mono_gc_base_init (void)
         * we used to do this only when running on valgrind,
         * but it happens also in other setups.
         */
-#if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK) && !defined(__native_client__)
+#if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
        {
                size_t size;
                void *sstart;
@@ -137,12 +139,6 @@ mono_gc_base_init (void)
                pthread_attr_getstack (&attr, &sstart, &size);
                pthread_attr_destroy (&attr); 
                /*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/
-#ifdef __ia64__
-               /*
-                * The calculation above doesn't seem to work on ia64, also we need to set
-                * GC_register_stackbottom as well, but don't know how.
-                */
-#else
                /* apparently with some linuxthreads implementations sstart can be NULL,
                 * fallback to the more imprecise method (bug# 78096).
                 */
@@ -155,7 +151,6 @@ mono_gc_base_init (void)
                        stack_bottom &= ~4095;
                        GC_stackbottom = (char*)stack_bottom;
                }
-#endif
        }
 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
                GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ());
@@ -170,8 +165,6 @@ mono_gc_base_init (void)
 
                GC_stackbottom = (char*)ss.ss_sp;
        }
-#elif defined(__native_client__)
-       /* Do nothing, GC_stackbottom is set correctly in libgc */
 #else
        {
                int dummy;
@@ -183,7 +176,11 @@ mono_gc_base_init (void)
        }
 #endif
 
-#if !defined(PLATFORM_ANDROID)
+       roots = g_hash_table_new (NULL, NULL);
+       default_push_other_roots = GC_push_other_roots;
+       GC_push_other_roots = mono_push_other_roots;
+
+#if !defined(HOST_ANDROID)
        /* If GC_no_dls is set to true, GC_find_limit is not called. This causes a seg fault on Android. */
        GC_no_dls = TRUE;
 #endif
@@ -198,6 +195,7 @@ mono_gc_base_init (void)
                                        log_finalizers = 1;
                                }
                        }
+                       g_free (env);
                }
        }
 
@@ -241,20 +239,16 @@ mono_gc_base_init (void)
                                */
                        }
                }
+               g_free (env);
                g_strfreev (opts);
        }
 
-       memset (&cb, 0, sizeof (cb));
-       cb.thread_register = boehm_thread_register;
-       cb.thread_unregister = boehm_thread_unregister;
-       cb.thread_detach = boehm_thread_detach;
-       cb.mono_method_is_critical = (gboolean (*)(void *))mono_runtime_is_critical_method;
-
-       mono_threads_init (&cb, sizeof (MonoThreadInfo));
+       mono_thread_callbacks_init ();
+       mono_thread_info_init (sizeof (MonoThreadInfo));
        mono_os_mutex_init (&mono_gc_lock);
        mono_os_mutex_init_recursive (&handle_section);
 
-       mono_thread_info_attach (&dummy);
+       mono_thread_info_attach ();
 
        GC_set_on_collection_event (on_gc_notification);
        GC_on_heap_resize = on_gc_heap_resize;
@@ -270,21 +264,21 @@ mono_gc_base_cleanup (void)
 
 /**
  * mono_gc_collect:
- * @generation: GC generation identifier
+ * \param generation GC generation identifier
  *
  * Perform a garbage collection for the given generation, higher numbers
  * mean usually older objects. Collecting a high-numbered generation
  * implies collecting also the lower-numbered generations.
- * The maximum value for @generation can be retrieved with a call to
- * mono_gc_max_generation(), so this function is usually called as:
+ * The maximum value for \p generation can be retrieved with a call to
+ * \c mono_gc_max_generation, so this function is usually called as:
  *
- *     mono_gc_collect (mono_gc_max_generation ());
+ * <code>mono_gc_collect (mono_gc_max_generation ());</code>
  */
 void
 mono_gc_collect (int generation)
 {
 #ifndef DISABLE_PERFCOUNTERS
-       mono_perfcounters->gc_induced++;
+       InterlockedIncrement (&mono_perfcounters->gc_induced);
 #endif
        GC_gcollect ();
 }
@@ -306,12 +300,12 @@ mono_gc_max_generation (void)
 
 /**
  * mono_gc_get_generation:
- * @object: a managed object
+ * \param object a managed object
  *
- * Get the garbage collector's generation that @object belongs to.
+ * Get the garbage collector's generation that \p object belongs to.
  * Use this has a hint only.
  *
- * Returns: a garbage collector generation number
+ * \returns a garbage collector generation number
  */
 int
 mono_gc_get_generation  (MonoObject *object)
@@ -321,12 +315,12 @@ mono_gc_get_generation  (MonoObject *object)
 
 /**
  * mono_gc_collection_count:
- * @generation: a GC generation number
+ * \param generation a GC generation number
  *
  * Get how many times a garbage collection has been performed
- * for the given @generation number.
+ * for the given \p generation number.
  *
- * Returns: the number of garbage collections
+ * \returns the number of garbage collections
  */
 int
 mono_gc_collection_count (int generation)
@@ -336,13 +330,13 @@ mono_gc_collection_count (int generation)
 
 /**
  * mono_gc_add_memory_pressure:
- * @value: amount of bytes
+ * \param value amount of bytes
  *
  * Adjust the garbage collector's view of how many bytes of memory
  * are indirectly referenced by managed objects (for example unmanaged
  * memory holding image or other binary data).
  * This is a hint only to the garbage collector algorithm.
- * Note that negative amounts of @value will decrease the memory
+ * Note that negative amounts of value will decrease the memory
  * pressure.
  */
 void
@@ -382,20 +376,14 @@ mono_gc_is_gc_thread (void)
        return GC_thread_is_registered ();
 }
 
-gboolean
-mono_gc_register_thread (void *baseptr)
-{
-       return mono_thread_info_attach (baseptr) != NULL;
-}
-
-static void*
-boehm_thread_register (MonoThreadInfo* info, void *baseptr)
+gpointer
+mono_gc_thread_attach (MonoThreadInfo* info)
 {
        struct GC_stack_base sb;
        int res;
 
        /* TODO: use GC_get_stack_base instead of baseptr. */
-       sb.mem_base = baseptr;
+       sb.mem_base = info->stack_end;
        res = GC_register_my_thread (&sb);
        if (res == GC_UNIMPLEMENTED)
            return NULL; /* Cannot happen with GC v7+. */
@@ -405,8 +393,8 @@ boehm_thread_register (MonoThreadInfo* info, void *baseptr)
        return info;
 }
 
-static void
-boehm_thread_unregister (MonoThreadInfo *p)
+void
+mono_gc_thread_detach_with_lock (MonoThreadInfo *p)
 {
        MonoNativeThreadId tid;
 
@@ -414,13 +402,14 @@ boehm_thread_unregister (MonoThreadInfo *p)
 
        if (p->runtime_thread)
                mono_threads_add_joinable_thread ((gpointer)tid);
+
+       mono_handle_stack_free (p->handle_stack);
 }
 
-static void
-boehm_thread_detach (MonoThreadInfo *p)
+gboolean
+mono_gc_thread_in_critical_region (MonoThreadInfo *info)
 {
-       if (mono_thread_internal_current_is_attached ())
-               mono_thread_detach_internal (mono_thread_internal_current ());
+       return FALSE;
 }
 
 gboolean
@@ -440,36 +429,42 @@ static gint64 gc_start_time;
 static void
 on_gc_notification (GC_EventType event)
 {
-       MonoGCEvent e = (MonoGCEvent)event;
+       MonoProfilerGCEvent e;
 
-       switch (e) {
-       case MONO_GC_EVENT_PRE_STOP_WORLD:
+       switch (event) {
+       case GC_EVENT_PRE_STOP_WORLD:
+               e = MONO_GC_EVENT_PRE_STOP_WORLD;
                MONO_GC_WORLD_STOP_BEGIN ();
                break;
 
-       case MONO_GC_EVENT_POST_STOP_WORLD:
+       case GC_EVENT_POST_STOP_WORLD:
+               e = MONO_GC_EVENT_POST_STOP_WORLD;
                MONO_GC_WORLD_STOP_END ();
                break;
 
-       case MONO_GC_EVENT_PRE_START_WORLD:
+       case GC_EVENT_PRE_START_WORLD:
+               e = MONO_GC_EVENT_PRE_START_WORLD;
                MONO_GC_WORLD_RESTART_BEGIN (1);
                break;
 
-       case MONO_GC_EVENT_POST_START_WORLD:
+       case GC_EVENT_POST_START_WORLD:
+               e = MONO_GC_EVENT_POST_START_WORLD;
                MONO_GC_WORLD_RESTART_END (1);
                break;
 
-       case MONO_GC_EVENT_START:
+       case GC_EVENT_START:
+               e = MONO_GC_EVENT_START;
                MONO_GC_BEGIN (1);
 #ifndef DISABLE_PERFCOUNTERS
                if (mono_perfcounters)
-                       mono_perfcounters->gc_collections0++;
+                       InterlockedIncrement (&mono_perfcounters->gc_collections0);
 #endif
-               gc_stats.major_gc_count ++;
+               InterlockedIncrement (&gc_stats.major_gc_count);
                gc_start_time = mono_100ns_ticks ();
                break;
 
-       case MONO_GC_EVENT_END:
+       case GC_EVENT_END:
+               e = MONO_GC_EVENT_END;
                MONO_GC_END (1);
 #if defined(ENABLE_DTRACE) && defined(__sun__)
                /* This works around a dtrace -G problem on Solaris.
@@ -482,29 +477,39 @@ on_gc_notification (GC_EventType event)
                if (mono_perfcounters) {
                        guint64 heap_size = GC_get_heap_size ();
                        guint64 used_size = heap_size - GC_get_free_bytes ();
-                       mono_perfcounters->gc_total_bytes = used_size;
-                       mono_perfcounters->gc_committed_bytes = heap_size;
-                       mono_perfcounters->gc_reserved_bytes = heap_size;
-                       mono_perfcounters->gc_gen0size = heap_size;
+                       /* FIXME: change these to InterlockedWrite64 () */
+                       UnlockedWrite64 (&mono_perfcounters->gc_total_bytes, used_size);
+                       UnlockedWrite64 (&mono_perfcounters->gc_committed_bytes, heap_size);
+                       UnlockedWrite64 (&mono_perfcounters->gc_reserved_bytes, heap_size);
+                       UnlockedWrite64 (&mono_perfcounters->gc_gen0size, heap_size);
                }
 #endif
-               gc_stats.major_gc_time += mono_100ns_ticks () - gc_start_time;
-               mono_trace_message (MONO_TRACE_GC, "gc took %d usecs", (mono_100ns_ticks () - gc_start_time) / 10);
+               UnlockedAdd64 (&gc_stats.major_gc_time, mono_100ns_ticks () - gc_start_time);
+               mono_trace_message (MONO_TRACE_GC, "gc took %" G_GINT64_FORMAT " usecs", (mono_100ns_ticks () - gc_start_time) / 10);
                break;
        default:
                break;
        }
 
-       mono_profiler_gc_event (e, 0);
+       switch (event) {
+       case GC_EVENT_MARK_START:
+       case GC_EVENT_MARK_END:
+       case GC_EVENT_RECLAIM_START:
+       case GC_EVENT_RECLAIM_END:
+               break;
+       default:
+               MONO_PROFILER_RAISE (gc_event, (e, 0));
+               break;
+       }
 
-       switch (e) {
-       case MONO_GC_EVENT_PRE_STOP_WORLD:
+       switch (event) {
+       case GC_EVENT_PRE_STOP_WORLD:
                mono_thread_info_suspend_lock ();
-               mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0);
+               MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0));
                break;
-       case MONO_GC_EVENT_POST_START_WORLD:
+       case GC_EVENT_POST_START_WORLD:
                mono_thread_info_suspend_unlock ();
-               mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0);
+               MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0));
                break;
        default:
                break;
@@ -518,19 +523,37 @@ on_gc_heap_resize (size_t new_size)
        guint64 heap_size = GC_get_heap_size ();
 #ifndef DISABLE_PERFCOUNTERS
        if (mono_perfcounters) {
-               mono_perfcounters->gc_committed_bytes = heap_size;
-               mono_perfcounters->gc_reserved_bytes = heap_size;
-               mono_perfcounters->gc_gen0size = heap_size;
+               /* FIXME: change these to InterlockedWrite64 () */
+               UnlockedWrite64 (&mono_perfcounters->gc_committed_bytes, heap_size);
+               UnlockedWrite64 (&mono_perfcounters->gc_reserved_bytes, heap_size);
+               UnlockedWrite64 (&mono_perfcounters->gc_gen0size, heap_size);
        }
 #endif
-       mono_profiler_gc_heap_resize (new_size);
+
+       MONO_PROFILER_RAISE (gc_resize, (new_size));
+}
+
+typedef struct {
+       char *start;
+       char *end;
+} RootData;
+
+static gpointer
+register_root (gpointer arg)
+{
+       RootData* root_data = arg;
+       g_hash_table_insert (roots, root_data->start, root_data->end);
+       return NULL;
 }
 
 int
 mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg)
 {
-       /* for some strange reason, they want one extra byte on the end */
-       GC_add_roots (start, start + size + 1);
+       RootData root_data;
+       root_data.start = start;
+       /* Boehm root processing requires one byte past end of region to be scanned */
+       root_data.end = start + size + 1;
+       GC_call_with_alloc_lock (register_root, &root_data);
 
        return TRUE;
 }
@@ -541,14 +564,32 @@ mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr
        return mono_gc_register_root (start, size, descr, source, msg);
 }
 
+static gpointer
+deregister_root (gpointer arg)
+{
+       gboolean removed = g_hash_table_remove (roots, arg);
+       g_assert (removed);
+       return NULL;
+}
+
 void
 mono_gc_deregister_root (char* addr)
 {
-#ifndef HOST_WIN32
-       /* FIXME: libgc doesn't define this work win32 for some reason */
-       /* FIXME: No size info */
-       GC_remove_roots (addr, addr + sizeof (gpointer) + 1);
-#endif
+       GC_call_with_alloc_lock (deregister_root, addr);
+}
+
+static void
+push_root (gpointer key, gpointer value, gpointer user_data)
+{
+       GC_push_all (key, value);
+}
+
+static void
+mono_push_other_roots (void)
+{
+       g_hash_table_foreach (roots, push_root, NULL);
+       if (default_push_other_roots)
+               default_push_other_roots ();
 }
 
 static void
@@ -617,6 +658,12 @@ mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits)
                return (gpointer)GC_make_descriptor ((GC_bitmap)bitmap, numbits);
 }
 
+void*
+mono_gc_make_vector_descr (void)
+{
+       return NULL;
+}
+
 void*
 mono_gc_make_root_descr_all_refs (int numbits)
 {
@@ -661,8 +708,8 @@ mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
                obj->vtable = vtable;
        }
 
-       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
-               mono_profiler_allocation (obj);
+       if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
+               MONO_PROFILER_RAISE (gc_allocation, (obj));
 
        return obj;
 }
@@ -695,8 +742,8 @@ mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
 
        obj->max_length = max_length;
 
-       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
-               mono_profiler_allocation (&obj->obj);
+       if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
+               MONO_PROFILER_RAISE (gc_allocation, (&obj->obj));
 
        return obj;
 }
@@ -732,8 +779,8 @@ mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uint
        if (bounds_size)
                obj->bounds = (MonoArrayBounds *) ((char *) obj + size - bounds_size);
 
-       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
-               mono_profiler_allocation (&obj->obj);
+       if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
+               MONO_PROFILER_RAISE (gc_allocation, (&obj->obj));
 
        return obj;
 }
@@ -750,8 +797,8 @@ mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
        obj->length = len;
        obj->chars [len] = 0;
 
-       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
-               mono_profiler_allocation (&obj->object);
+       if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
+               MONO_PROFILER_RAISE (gc_allocation, (&obj->object));
 
        return obj;
 }
@@ -1127,11 +1174,8 @@ mono_gc_is_critical_method (MonoMethod *method)
  * @klass. The method will typically have an thread-local inline allocation sequence.
  * The signature of the called method is:
  *     object allocate (MonoVTable *vtable)
- * Some of the logic here is similar to mono_class_get_allocation_ftn () i object.c,
- * keep in sync.
  * The thread local alloc logic is taken from libgc/pthread_support.c.
  */
-
 MonoMethod*
 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
 {
@@ -1147,7 +1191,7 @@ mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean know
                return NULL;
        if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass))
                return NULL;
-       if (mono_profiler_get_events () & (MONO_PROFILE_ALLOCATIONS | MONO_PROFILE_STATISTICAL))
+       if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
                return NULL;
        if (klass->rank)
                return NULL;
@@ -1313,18 +1357,23 @@ mono_gc_is_moving (void)
 gboolean
 mono_gc_is_disabled (void)
 {
-       if (GC_dont_gc || g_getenv ("GC_DONT_GC"))
+       if (GC_dont_gc || g_hasenv ("GC_DONT_GC"))
                return TRUE;
        else
                return FALSE;
 }
 
 void
-mono_gc_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, unsigned bitmap)
+mono_gc_wbarrier_range_copy (gpointer _dest, gpointer _src, int size)
 {
        g_assert_not_reached ();
 }
 
+void*
+mono_gc_get_range_copy_func (void)
+{
+       return &mono_gc_wbarrier_range_copy;
+}
 
 guint8*
 mono_gc_get_card_table (int *shift_bits, gpointer *card_mask)
@@ -1689,29 +1738,29 @@ alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
        }
 
 #ifndef DISABLE_PERFCOUNTERS
-       mono_perfcounters->gc_num_handles++;
+       InterlockedIncrement (&mono_perfcounters->gc_num_handles);
 #endif
        unlock_handles (handles);
        res = MONO_GC_HANDLE (slot, handles->type);
-       mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
+       MONO_PROFILER_RAISE (gc_handle_created, (res, handles->type, obj));
        return res;
 }
 
 /**
  * mono_gchandle_new:
- * @obj: managed object to get a handle for
- * @pinned: whether the object should be pinned
+ * \param obj managed object to get a handle for
+ * \param pinned whether the object should be pinned
  *
  * This returns a handle that wraps the object, this is used to keep a
  * reference to a managed object from the unmanaged world and preventing the
  * object from being disposed.
  * 
- * If @pinned is false the address of the object can not be obtained, if it is
+ * If \p pinned is false the address of the object can not be obtained, if it is
  * true the address of the object can be obtained.  This will also pin the
  * object so it will not be possible by a moving garbage collector to move the
  * object. 
  * 
- * Returns: a handle that can be used to access the object from
+ * \returns a handle that can be used to access the object from
  * unmanaged code.
  */
 guint32
@@ -1722,23 +1771,23 @@ mono_gchandle_new (MonoObject *obj, gboolean pinned)
 
 /**
  * mono_gchandle_new_weakref:
- * @obj: managed object to get a handle for
- * @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.
+ * \param obj managed object to get a handle for
+ * \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.
  *
  * This returns a weak handle that wraps the object, this is used to
  * keep a reference to a managed object from the unmanaged world.
- * Unlike the mono_gchandle_new the object can be reclaimed by the
+ * Unlike the \c mono_gchandle_new the object can be reclaimed by the
  * garbage collector.  In this case the value of the GCHandle will be
  * set to zero.
  * 
- * If @track_resurrection is TRUE the object will be tracked through
+ * If \p track_resurrection is TRUE the object will be tracked through
  * finalization and if the object is resurrected during the execution
  * of the finalizer, then the returned weakref will continue to hold
- * a reference to the object.   If @track_resurrection is FALSE, then
+ * a reference to the object.   If \p track_resurrection is FALSE, then
  * the weak reference's target will become NULL as soon as the object
  * is passed on to the finalizer.
  * 
- * Returns: a handle that can be used to access the object from
+ * \returns a handle that can be used to access the object from
  * unmanaged code.
  */
 guint32
@@ -1749,12 +1798,12 @@ mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
 
 /**
  * mono_gchandle_get_target:
- * @gchandle: a GCHandle's handle.
+ * \param gchandle a GCHandle's handle.
  *
- * The handle was previously created by calling `mono_gchandle_new` or
- * `mono_gchandle_new_weakref`.
+ * The handle was previously created by calling \c mono_gchandle_new or
+ * \c mono_gchandle_new_weakref.
  *
- * Returns: A pointer to the `MonoObject*` represented by the handle or
+ * \returns A pointer to the \c MonoObject* represented by the handle or
  * NULL for a collected object if using a weakref handle.
  */
 MonoObject*
@@ -1819,13 +1868,13 @@ mono_gc_is_null (void)
 
 /**
  * mono_gchandle_is_in_domain:
- * @gchandle: a GCHandle's handle.
- * @domain: An application domain.
+ * \param gchandle a GCHandle's handle.
+ * \param domain An application domain.
  *
- * Use this function to determine if the @gchandle points to an
- * object allocated in the specified @domain.
+ * Use this function to determine if the \p gchandle points to an
+ * object allocated in the specified \p domain.
  *
- * Returns: TRUE if the object wrapped by the @gchandle belongs to the specific @domain.
+ * \returns TRUE if the object wrapped by the \p gchandle belongs to the specific \p domain.
  */
 gboolean
 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
@@ -1859,9 +1908,9 @@ mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
 
 /**
  * mono_gchandle_free:
- * @gchandle: a GCHandle's handle.
+ * \param gchandle a GCHandle's handle.
  *
- * Frees the @gchandle handle.  If there are no outstanding
+ * Frees the \p gchandle handle.  If there are no outstanding
  * references, the garbage collector can reclaim the memory of the
  * object wrapped. 
  */
@@ -1887,16 +1936,16 @@ mono_gchandle_free (guint32 gchandle)
                /* print a warning? */
        }
 #ifndef DISABLE_PERFCOUNTERS
-       mono_perfcounters->gc_num_handles--;
+       InterlockedDecrement (&mono_perfcounters->gc_num_handles);
 #endif
        /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
        unlock_handles (handles);
-       mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
+       MONO_PROFILER_RAISE (gc_handle_deleted, (gchandle, handles->type));
 }
 
 /**
  * mono_gchandle_free_domain:
- * @domain: domain that is unloading
+ * \param domain domain that is unloading
  *
  * Function used internally to cleanup any GC handle for objects belonging
  * to the specified domain during appdomain unload.