-/*
- * sgen-mono.c: SGen features specific to Mono.
+/**
+ * \file
+ * SGen features specific to Mono.
*
* Copyright (C) 2014 Xamarin Inc
*
#include "sgen/sgen-client.h"
#include "sgen/sgen-cardtable.h"
#include "sgen/sgen-pinning.h"
-#include "sgen/sgen-thread-pool.h"
+#include "sgen/sgen-workers.h"
#include "metadata/marshal.h"
#include "metadata/method-builder.h"
#include "metadata/abi-details.h"
/**
* mono_gc_wbarrier_object_copy:
*
- * Write barrier to call when obj is the result of a clone or copy of an object.
+ * Write barrier to call when \p obj is the result of a clone or copy of an object.
*/
void
mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
sgen_get_remset ()->wbarrier_object_copy (obj, src);
}
+/**
+ * mono_gc_wbarrier_set_arrayref:
+ */
void
mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* value)
{
sgen_get_remset ()->wbarrier_set_field ((GCObject*)arr, slot_ptr, value);
}
+/**
+ * mono_gc_wbarrier_set_field:
+ */
void
mono_gc_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* value)
{
}
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)
{
- sgen_wbarrier_value_copy_bitmap (_dest, _src, size, bitmap);
+ sgen_wbarrier_range_copy (_dest, _src, size);
+}
+
+void*
+mono_gc_get_range_copy_func (void)
+{
+ return sgen_get_remset ()->wbarrier_range_copy;
}
int
mono_gc_run_finalize (obj, NULL);
}
+/**
+ * mono_gc_invoke_finalizers:
+ */
int
mono_gc_invoke_finalizers (void)
{
return sgen_gc_invoke_finalizers ();
}
+/**
+ * mono_gc_pending_finalizers:
+ */
MonoBoolean
mono_gc_pending_finalizers (void)
{
/**
* mono_gc_finalizers_for_domain:
- * @domain: the unloading appdomain
- * @out_array: output array
- * @out_size: size of output array
- *
- * Enqueue for finalization all objects that belong to the unloading appdomain @domain
- * @suspend is used for early termination of the enqueuing process.
+ * \param domain the unloading appdomain
+ * \param out_array output array
+ * \param out_size size of output array
+ * Enqueue for finalization all objects that belong to the unloading appdomain \p domain.
+ * \p suspend is used for early termination of the enqueuing process.
*/
void
mono_gc_finalize_domain (MonoDomain *domain)
return obj;
}
+/**
+ * mono_gc_alloc_fixed:
+ */
void*
mono_gc_alloc_fixed (size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg)
{
return res;
}
+/**
+ * mono_gc_free_fixed:
+ */
void
mono_gc_free_fixed (void* addr)
{
{
int p_var, size_var, real_size_var, thread_var G_GNUC_UNUSED;
gboolean slowpath = variant == MANAGED_ALLOCATOR_SLOW_PATH;
- guint32 slowpath_branch, max_size_branch;
+ guint32 fastpath_branch, max_size_branch, no_oom_branch;
MonoMethodBuilder *mb;
MonoMethod *res;
MonoMethodSignature *csig;
/* if (G_LIKELY (new_next < tlab_temp_end)) */
mono_mb_emit_ldloc (mb, new_next_var);
EMIT_TLS_ACCESS_TEMP_END (mb, thread_var);
- slowpath_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLT_UN_S);
+ fastpath_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLT_UN_S);
/* Slowpath */
if (atype != ATYPE_SMALL)
} else {
g_assert_not_reached ();
}
+
+ /* if (ret == NULL) throw OOM; */
+ mono_mb_emit_byte (mb, CEE_DUP);
+ no_oom_branch = mono_mb_emit_branch (mb, CEE_BRTRUE);
+ mono_mb_emit_exception (mb, "OutOfMemoryException", NULL);
+
+ mono_mb_patch_branch (mb, no_oom_branch);
mono_mb_emit_byte (mb, CEE_RET);
/* Fastpath */
- mono_mb_patch_short_branch (mb, slowpath_branch);
+ mono_mb_patch_short_branch (mb, fastpath_branch);
/* FIXME: Memory barrier */
return FALSE;
}
-/*
- * Cardtable scanning
- */
-
-#define MWORD_MASK (sizeof (mword) - 1)
-
-static inline int
-find_card_offset (mword card)
-{
-/*XXX Use assembly as this generates some pretty bad code */
-#if defined(__i386__) && defined(__GNUC__)
- return (__builtin_ffs (card) - 1) / 8;
-#elif defined(__x86_64__) && defined(__GNUC__)
- return (__builtin_ffsll (card) - 1) / 8;
-#elif defined(__s390x__)
- return (__builtin_ffsll (GUINT64_TO_LE(card)) - 1) / 8;
-#else
- int i;
- guint8 *ptr = (guint8 *) &card;
- for (i = 0; i < sizeof (mword); ++i) {
- if (ptr[i])
- return i;
- }
- return 0;
-#endif
-}
-
-static guint8*
-find_next_card (guint8 *card_data, guint8 *end)
-{
- mword *cards, *cards_end;
- mword card;
-
- while ((((mword)card_data) & MWORD_MASK) && card_data < end) {
- if (*card_data)
- return card_data;
- ++card_data;
- }
-
- if (card_data == end)
- return end;
-
- cards = (mword*)card_data;
- cards_end = (mword*)((mword)end & ~MWORD_MASK);
- while (cards < cards_end) {
- card = *cards;
- if (card)
- return (guint8*)cards + find_card_offset (card);
- ++cards;
- }
-
- card_data = (guint8*)cards_end;
- while (card_data < end) {
- if (*card_data)
- return card_data;
- ++card_data;
- }
-
- return end;
-}
-
#define ARRAY_OBJ_INDEX(ptr,array,elem_size) (((char*)(ptr) - ((char*)(array) + G_STRUCT_OFFSET (MonoArray, vector))) / (elem_size))
gboolean
LOOP_HEAD:
#endif
- card_data = find_next_card (card_data, card_data_end);
- for (; card_data < card_data_end; card_data = find_next_card (card_data + 1, card_data_end)) {
+ card_data = sgen_find_next_card (card_data, card_data_end);
+ for (; card_data < card_data_end; card_data = sgen_find_next_card (card_data + 1, card_data_end)) {
size_t index;
size_t idx = (card_data - card_base) + extra_idx;
char *start = (char*)(obj_start + idx * CARD_SIZE_IN_BYTES);
}
break;
}
+ case ROOT_DESC_VECTOR: {
+ void **p;
+
+ for (p = start_root; p < end_root; p++) {
+ if (*p)
+ add_profile_gc_root (report, *p, MONO_PROFILE_GC_ROOT_OTHER, 0);
+ }
+ break;
+ }
case ROOT_DESC_USER: {
MonoGCRootMarkFunc marker = (MonoGCRootMarkFunc)sgen_get_user_descriptor_func (desc);
root_report = report;
* lock-free data structure for the queue as multiple threads will be
* adding to it at the same time.
*/
- if (sgen_thread_pool_is_thread_pool_thread (mono_native_thread_id_get ())) {
+ if (sgen_workers_is_worker_thread (mono_native_thread_id_get ())) {
sgen_pointer_queue_add (&moved_objects_queue, obj);
sgen_pointer_queue_add (&moved_objects_queue, destination);
} else {
/**
* mono_gc_walk_heap:
- * @flags: flags for future use
- * @callback: a function pointer called for each object in the heap
- * @data: a user data pointer that is passed to callback
- *
- * This function can be used to iterate over all the live objects in the heap:
- * for each object, @callback is invoked, providing info about the object's
+ * \param flags flags for future use
+ * \param callback a function pointer called for each object in the heap
+ * \param data a user data pointer that is passed to callback
+ * This function can be used to iterate over all the live objects in the heap;
+ * for each object, \p callback is invoked, providing info about the object's
* location in memory, its class, its size and the objects it references.
- * For each referenced object it's offset from the object address is
+ * For each referenced object its offset from the object address is
* reported in the offsets array.
* The object references may be buffered, so the callback may be invoked
* multiple times for the same object: in all but the first call, the size
* argument will be zero.
- * Note that this function can be only called in the #MONO_GC_EVENT_PRE_START_WORLD
+ * Note that this function can be only called in the \c MONO_GC_EVENT_PRE_START_WORLD
* profiler event handler.
- *
- * Returns: a non-zero value if the GC doesn't support heap walking
+ * \returns a non-zero value if the GC doesn't support heap walking
*/
int
mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
mono_thread_detach_internal (mono_thread_internal_current ());
}
+/**
+ * mono_gc_register_thread:
+ */
gboolean
mono_gc_register_thread (void *baseptr)
{
return mono_thread_info_attach (baseptr) != NULL;
}
+/**
+ * mono_gc_is_gc_thread:
+ */
gboolean
mono_gc_is_gc_thread (void)
{
return obj;
}
+typedef struct {
+ void **start_nursery;
+ void **end_nursery;
+} PinHandleStackInteriorPtrData;
+
+/* Called when we're scanning the handle stack imprecisely and we encounter a pointer into the
+ middle of an object.
+ */
+static void
+pin_handle_stack_interior_ptrs (void **ptr_slot, void *user_data)
+{
+ PinHandleStackInteriorPtrData *ud = (PinHandleStackInteriorPtrData *)user_data;
+ sgen_conservatively_pin_objects_from (ptr_slot, ptr_slot+1, ud->start_nursery, ud->end_nursery, PIN_TYPE_STACK);
+}
+
+
/*
* Mark from thread stacks and registers.
*/
}
}
}
- if (precise && info->client_info.info.handle_stack) {
- mono_handle_stack_scan ((HandleStack*)info->client_info.info.handle_stack, (GcScanFunc)ctx.ops->copy_or_mark_object, ctx.queue);
+ if (info->client_info.info.handle_stack) {
+ /*
+ Make two passes over the handle stack. On the imprecise pass, pin all
+ objects where the handle points into the interior of the object. On the
+ precise pass, copy or mark all the objects that have handles to the
+ beginning of the object.
+ */
+ if (precise)
+ mono_handle_stack_scan ((HandleStack*)info->client_info.info.handle_stack, (GcScanFunc)ctx.ops->copy_or_mark_object, ctx.queue, precise);
+ else {
+ PinHandleStackInteriorPtrData ud = { .start_nursery = start_nursery,
+ .end_nursery = end_nursery,
+ };
+ mono_handle_stack_scan ((HandleStack*)info->client_info.info.handle_stack, pin_handle_stack_interior_ptrs, &ud, precise);
+ }
}
} FOREACH_THREAD_END
}
mono_gc_get_nursery (int *shift_bits, size_t *size)
{
*size = sgen_nursery_size;
- *shift_bits = DEFAULT_NURSERY_BITS;
+ *shift_bits = sgen_nursery_bits;
return sgen_get_nursery_start ();
}
/**
* mono_gchandle_is_in_domain:
- * @gchandle: a GCHandle's handle.
- * @domain: An application domain.
- *
- * Returns: TRUE if the object wrapped by the @gchandle belongs to the specific @domain.
+ * \param gchandle a GCHandle's handle.
+ * \param domain An application 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)
/**
* mono_gchandle_free_domain:
- * @unloading: domain that is unloading
+ * \param unloading domain that is unloading
*
* Function used internally to cleanup any GC handle for objects belonging
* to the specified domain during appdomain unload.
static gboolean gc_inited;
+/**
+ * mono_gc_base_init:
+ */
void
mono_gc_base_init (void)
{
void
mono_gc_base_cleanup (void)
{
- sgen_thread_pool_shutdown ();
+ sgen_thread_pool_shutdown (major_collector.get_sweep_pool ());
+
+ sgen_workers_shutdown ();
// We should have consumed any outstanding moves.
g_assert (sgen_pointer_queue_is_empty (&moved_objects_queue));