return FALSE;
}
+gboolean
+mono_gc_object_older_than (MonoObject *object, int generation) {
+ return FALSE;
+}
+
#endif /* no Boehm GC */
#define __MONO_METADATA_GC_INTERNAL_H__
#include <glib.h>
+#include <mono/utils/gc_wrapper.h>
#include <mono/metadata/object-internals.h>
#include <mono/metadata/threads-types.h>
#include <mono/sgen/gc-internal-agnostic.h>
/* If set, do not run finalizers. */
extern gboolean do_not_finalize;
+gboolean mono_gc_object_older_than (MonoObject *object, int generation);
+
#endif /* __MONO_METADATA_GC_INTERNAL_H__ */
#include <mono/metadata/threads-types.h>
#include <mono/metadata/threadpool-ms.h>
#include <mono/sgen/sgen-conf.h>
+#include <mono/sgen/sgen-gc.h>
#include <mono/utils/mono-logger-internal.h>
#include <mono/metadata/gc-internal.h>
#include <mono/metadata/marshal.h> /* for mono_delegate_free_ftnptr () */
#define mono_allocator_lock() mono_mutex_lock (&allocator_section)
#define mono_allocator_unlock() mono_mutex_unlock (&allocator_section)
static mono_mutex_t allocator_section;
-static mono_mutex_t handle_section;
-typedef enum {
- HANDLE_WEAK,
- HANDLE_WEAK_TRACK,
- HANDLE_NORMAL,
- HANDLE_PINNED
-} HandleType;
+#ifndef HAVE_SGEN_GC
+static mono_mutex_t handle_section;
+#endif
-static HandleType mono_gchandle_get_type (guint32 gchandle);
+#define GC_HANDLE_TYPE_SHIFT (3)
+#define GC_HANDLE_TYPE_MASK ((1 << GC_HANDLE_TYPE_SHIFT) - 1)
+#define GC_HANDLE_TYPE(x) (((x) & GC_HANDLE_TYPE_MASK) - 1)
+#define GC_HANDLE_SLOT(x) ((x) >> GC_HANDLE_TYPE_SHIFT)
+#define GC_HANDLE_TYPE_IS_WEAK(x) ((x) <= HANDLE_WEAK_TRACK)
+#define GC_HANDLE_TAG(slot, type) (((slot) << GC_HANDLE_TYPE_SHIFT) | (((type) & GC_HANDLE_TYPE_MASK) + 1))
MonoObject *
ves_icall_System_GCHandle_GetTarget (guint32 handle)
{
MonoObject *obj;
- if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
+ if (GC_HANDLE_TYPE (handle) != HANDLE_PINNED)
return (gpointer)-2;
obj = mono_gchandle_get_target (handle);
if (obj) {
gpointer *entries;
guint32 size;
guint8 type;
- guint slot_hint : 24; /* starting slot for search */
+ guint slot_hint : 24; /* starting slot for search in bitmap */
/* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
/* we alloc this only for weak refs, since we can get the domain directly in the other cases */
guint16 *domain_ids;
} HandleData;
+#define BITMAP_SIZE (sizeof (*((HandleData *)NULL)->bitmap) * CHAR_BIT)
+
+static inline gboolean
+slot_occupied (HandleData *handles, guint slot) {
+ return handles->bitmap [slot / BITMAP_SIZE] & (1 << (slot % BITMAP_SIZE));
+}
+
+static inline void
+vacate_slot (HandleData *handles, guint slot) {
+ handles->bitmap [slot / BITMAP_SIZE] &= ~(1 << (slot % BITMAP_SIZE));
+}
+
+static inline void
+occupy_slot (HandleData *handles, guint slot) {
+ handles->bitmap [slot / BITMAP_SIZE] |= 1 << (slot % BITMAP_SIZE);
+}
+
+#define EMPTY_HANDLE_DATA(type) {NULL, NULL, 0, (type), 0}
+
/* weak and weak-track arrays will be allocated in malloc memory
*/
static HandleData gc_handles [] = {
- {NULL, NULL, 0, HANDLE_WEAK, 0},
- {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
- {NULL, NULL, 0, HANDLE_NORMAL, 0},
- {NULL, NULL, 0, HANDLE_PINNED, 0}
+ EMPTY_HANDLE_DATA (HANDLE_WEAK),
+ EMPTY_HANDLE_DATA (HANDLE_WEAK_TRACK),
+ EMPTY_HANDLE_DATA (HANDLE_NORMAL),
+ EMPTY_HANDLE_DATA (HANDLE_PINNED)
};
+
+#ifdef HAVE_SGEN_GC
+#define lock_handles(handles) sgen_gc_lock ()
+#define unlock_handles(handles) sgen_gc_unlock ()
+#else
#define lock_handles(handles) do { \
MONO_TRY_BLOCKING; \
mono_mutex_lock (&handle_section); \
MONO_FINISH_TRY_BLOCKING; \
} while (0)
-
#define unlock_handles(handles) mono_mutex_unlock (&handle_section)
+#endif
static int
find_first_unset (guint32 bitmap)
return mono_gc_make_root_descr_all_refs (numbits);
}
-static guint32
-alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
+static void
+handle_data_alloc_entries (HandleData *handles)
{
- gint slot, i;
- guint32 res;
- lock_handles (handles);
- if (!handles->size) {
- handles->size = 32;
- if (handles->type > HANDLE_WEAK_TRACK) {
- handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED), MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
- } else {
- handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
- handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
- }
- handles->bitmap = g_malloc0 (handles->size / 8);
- }
- i = -1;
- for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
- if (handles->bitmap [slot] != 0xffffffff) {
- i = find_first_unset (handles->bitmap [slot]);
- handles->slot_hint = slot;
- break;
- }
- }
- if (i == -1 && handles->slot_hint != 0) {
- for (slot = 0; slot < handles->slot_hint; ++slot) {
- if (handles->bitmap [slot] != 0xffffffff) {
- i = find_first_unset (handles->bitmap [slot]);
- handles->slot_hint = slot;
- break;
- }
- }
+ handles->size = 32;
+ if (GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
+ handles->entries = g_malloc0 (sizeof (*handles->entries) * handles->size);
+ handles->domain_ids = g_malloc0 (sizeof (*handles->domain_ids) * handles->size);
+ } else {
+ handles->entries = mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED), MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
}
- if (i == -1) {
- guint32 *new_bitmap;
- guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
-
- /* resize and copy the bitmap */
- new_bitmap = g_malloc0 (new_size / 8);
- memcpy (new_bitmap, handles->bitmap, handles->size / 8);
- g_free (handles->bitmap);
- handles->bitmap = new_bitmap;
+ handles->bitmap = g_malloc0 (handles->size / CHAR_BIT);
+}
- /* resize and copy the entries */
- if (handles->type > HANDLE_WEAK_TRACK) {
- gpointer *entries;
+static gint
+handle_data_next_unset (HandleData *handles)
+{
+ gint slot;
+ for (slot = handles->slot_hint; slot < handles->size / BITMAP_SIZE; ++slot) {
+ if (handles->bitmap [slot] == 0xffffffff)
+ continue;
+ handles->slot_hint = slot;
+ return find_first_unset (handles->bitmap [slot]);
+ }
+ return -1;
+}
- entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED), MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
- mono_gc_memmove_aligned (entries, handles->entries, sizeof (gpointer) * handles->size);
+static gint
+handle_data_first_unset (HandleData *handles)
+{
+ gint slot;
+ for (slot = 0; slot < handles->slot_hint; ++slot) {
+ if (handles->bitmap [slot] == 0xffffffff)
+ continue;
+ handles->slot_hint = slot;
+ return find_first_unset (handles->bitmap [slot]);
+ }
+ return -1;
+}
- mono_gc_free_fixed (handles->entries);
- handles->entries = entries;
- } else {
- gpointer *entries;
- guint16 *domain_ids;
- domain_ids = g_malloc0 (sizeof (guint16) * new_size);
- entries = g_malloc0 (sizeof (gpointer) * new_size);
- memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
- for (i = 0; i < handles->size; ++i) {
- MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
- if (obj) {
- mono_gc_weak_link_add (&(entries [i]), obj, track);
- mono_gc_weak_link_remove (&(handles->entries [i]), track);
- } else {
- g_assert (!handles->entries [i]);
- }
+/* Returns the index of the current slot in the bitmap. */
+static void
+handle_data_grow (HandleData *handles, gboolean track)
+{
+ guint32 *new_bitmap;
+ guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
+
+ /* resize and copy the bitmap */
+ new_bitmap = g_malloc0 (new_size / CHAR_BIT);
+ memcpy (new_bitmap, handles->bitmap, handles->size / CHAR_BIT);
+ g_free (handles->bitmap);
+ handles->bitmap = new_bitmap;
+
+ /* resize and copy the entries */
+ if (GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
+ gpointer *entries;
+ guint16 *domain_ids;
+ gint i;
+ domain_ids = g_malloc0 (sizeof (*handles->domain_ids) * new_size);
+ entries = g_malloc0 (sizeof (*handles->entries) * new_size);
+ memcpy (domain_ids, handles->domain_ids, sizeof (*handles->domain_ids) * handles->size);
+ for (i = 0; i < handles->size; ++i) {
+ MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
+ if (obj) {
+ mono_gc_weak_link_add (&(entries [i]), obj, track);
+ mono_gc_weak_link_remove (&(handles->entries [i]), track);
+ } else {
+ g_assert (!handles->entries [i]);
}
- g_free (handles->entries);
- g_free (handles->domain_ids);
- handles->entries = entries;
- handles->domain_ids = domain_ids;
}
+ g_free (handles->entries);
+ g_free (handles->domain_ids);
+ handles->entries = entries;
+ handles->domain_ids = domain_ids;
+ } else {
+ gpointer *entries;
+ entries = mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED), MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
+ mono_gc_memmove_aligned (entries, handles->entries, sizeof (*handles->entries) * handles->size);
+ mono_gc_free_fixed (handles->entries);
+ handles->entries = entries;
+ }
+ handles->slot_hint = handles->size / BITMAP_SIZE;
+ handles->size = new_size;
+}
- /* set i and slot to the next free position */
+static guint32
+alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
+{
+ gint slot, i;
+ guint32 res;
+ lock_handles (handles);
+ if (!handles->size)
+ handle_data_alloc_entries (handles);
+ i = handle_data_next_unset (handles);
+ if (i == -1 && handles->slot_hint != 0)
+ i = handle_data_first_unset (handles);
+ if (i == -1) {
+ handle_data_grow (handles, track);
i = 0;
- slot = (handles->size + 1) / 32;
- handles->slot_hint = handles->size + 1;
- handles->size = new_size;
}
- handles->bitmap [slot] |= 1 << i;
- slot = slot * 32 + i;
+ slot = handles->slot_hint * BITMAP_SIZE + i;
+ occupy_slot (handles, slot);
handles->entries [slot] = NULL;
- if (handles->type <= HANDLE_WEAK_TRACK) {
+ if (GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
/*FIXME, what to use when obj == null?*/
handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
if (obj)
mono_perfcounters->gc_num_handles++;
#endif
unlock_handles (handles);
- /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
- res = (slot << 3) | (handles->type + 1);
+ res = GC_HANDLE_TAG (slot, handles->type);
mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
return res;
}
+void
+mono_gchandle_iterate (GCHandleType handle_type, int max_generation, gpointer callback(gpointer *, GCHandleType, gpointer), gpointer user)
+{
+ HandleData *handle_data = &gc_handles [handle_type];
+ size_t i;
+ lock_handles (handle_data);
+ for (i = 0; i < handle_data->size; ++i) {
+ gpointer *entry = &handle_data->entries [i];
+ /* Table must contain no garbage pointers. */
+ g_assert (*entry ? slot_occupied (handle_data, i) : TRUE);
+ if (!*entry || !slot_occupied (handle_data, i) || mono_gc_object_older_than (REVEAL_POINTER (*entry), max_generation))
+ continue;
+ *entry = callback (entry, handle_type, user);
+ }
+ unlock_handles (handle_data);
+}
+
/**
* mono_gchandle_new:
* @obj: managed object to get a handle for
return handle;
}
-static HandleType
-mono_gchandle_get_type (guint32 gchandle)
-{
- guint type = (gchandle & 7) - 1;
-
- return type;
-}
-
/**
* mono_gchandle_get_target:
* @gchandle: a GCHandle's handle.
MonoObject*
mono_gchandle_get_target (guint32 gchandle)
{
- guint slot = gchandle >> 3;
- guint type = (gchandle & 7) - 1;
+ guint slot = GC_HANDLE_SLOT (gchandle);
+ guint type = GC_HANDLE_TYPE (gchandle);
HandleData *handles = &gc_handles [type];
MonoObject *obj = NULL;
- if (type > 3)
+ if (type >= HANDLE_TYPE_MAX)
return NULL;
+
lock_handles (handles);
- if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
- if (handles->type <= HANDLE_WEAK_TRACK) {
+ if (slot < handles->size && slot_occupied (handles, slot)) {
+ if (GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
obj = mono_gc_weak_link_get (&handles->entries [slot]);
} else {
obj = handles->entries [slot];
static void
mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
{
- guint slot = gchandle >> 3;
- guint type = (gchandle & 7) - 1;
+ guint slot = GC_HANDLE_SLOT (gchandle);
+ guint type = GC_HANDLE_TYPE (gchandle);
HandleData *handles = &gc_handles [type];
- if (type > 3)
- return;
+ g_assert (type < HANDLE_TYPE_MAX);
lock_handles (handles);
- if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
- if (handles->type <= HANDLE_WEAK_TRACK) {
+ if (slot < handles->size && slot_occupied (handles, slot)) {
+ if (GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
if (handles->entries [slot])
mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
if (obj)
gboolean
mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
{
- guint slot = gchandle >> 3;
- guint type = (gchandle & 7) - 1;
+ guint slot = GC_HANDLE_SLOT (gchandle);
+ guint type = GC_HANDLE_TYPE (gchandle);
HandleData *handles = &gc_handles [type];
gboolean result = FALSE;
- if (type > 3)
+
+ if (type >= HANDLE_TYPE_MAX)
return FALSE;
+
lock_handles (handles);
- if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
- if (handles->type <= HANDLE_WEAK_TRACK) {
+ if (slot < handles->size && slot_occupied (handles, slot)) {
+ if (GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
result = domain->domain_id == handles->domain_ids [slot];
} else {
MonoObject *obj;
void
mono_gchandle_free (guint32 gchandle)
{
- guint slot = gchandle >> 3;
- guint type = (gchandle & 7) - 1;
+ guint slot = GC_HANDLE_SLOT (gchandle);
+ guint type = GC_HANDLE_TYPE (gchandle);
HandleData *handles = &gc_handles [type];
- if (type > 3)
+ if (type >= HANDLE_TYPE_MAX)
return;
lock_handles (handles);
- if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
- if (handles->type <= HANDLE_WEAK_TRACK) {
+ if (slot < handles->size && slot_occupied (handles, slot)) {
+ if (GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
if (handles->entries [slot])
mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
} else {
handles->entries [slot] = NULL;
}
- handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
+ vacate_slot (handles, slot);
} else {
/* print a warning? */
}
{
guint type;
- for (type = 0; type < 3; ++type) {
+ for (type = HANDLE_TYPE_MIN; type < HANDLE_PINNED; ++type) {
guint slot;
HandleData *handles = &gc_handles [type];
lock_handles (handles);
for (slot = 0; slot < handles->size; ++slot) {
- if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
+ if (!slot_occupied (handles, slot))
continue;
- if (type <= HANDLE_WEAK_TRACK) {
+ if (GC_HANDLE_TYPE_IS_WEAK (type)) {
if (domain->domain_id == handles->domain_ids [slot]) {
- handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
+ vacate_slot (handles, slot);
if (handles->entries [slot])
mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
}
} else {
if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
- handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
+ vacate_slot (handles, slot);
handles->entries [slot] = NULL;
}
}
void
mono_gc_init (void)
{
+#ifndef HAVE_SGEN_GC
mono_mutex_init_recursive (&handle_section);
+#endif
mono_mutex_init_recursive (&allocator_section);
mono_mutex_init_recursive (&finalizer_mutex);
mono_reference_queue_cleanup ();
+#ifndef HAVE_SGEN_GC
+ mono_mutex_destroy (&handle_section);
+#endif
+
mono_mutex_destroy (&allocator_section);
mono_mutex_destroy (&finalizer_mutex);
mono_mutex_destroy (&reference_queue_mutex);
void
mono_gc_mutex_cleanup (void)
{
+#ifndef HAVE_SGEN_GC
mono_mutex_destroy (&handle_section);
+#endif
}
gboolean
RefQueueEntry **iter = &queue->queue;
RefQueueEntry *entry;
while ((entry = *iter)) {
-#ifdef HAVE_SGEN_GC
- if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
- mono_gc_weak_link_remove (&entry->dis_link, TRUE);
-#else
if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
mono_gchandle_free ((guint32)entry->gchandle);
-#endif
ref_list_remove_element (iter, entry);
queue->callback (entry->user_data);
g_free (entry);
RefQueueEntry *entry;
while ((entry = *iter)) {
if (entry->domain == domain) {
-#ifdef HAVE_SGEN_GC
- mono_gc_weak_link_remove (&entry->dis_link, TRUE);
-#else
mono_gchandle_free ((guint32)entry->gchandle);
-#endif
ref_list_remove_element (iter, entry);
queue->callback (entry->user_data);
g_free (entry);
entry->user_data = user_data;
entry->domain = mono_object_domain (obj);
-#ifdef HAVE_SGEN_GC
- mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
-#else
entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
mono_object_register_finalizer (obj);
-#endif
ref_list_push (&queue->queue, entry);
return TRUE;
to_recycle++;
} else {
if (!monitor_is_on_freelist (mon->data)) {
- MonoObject *holder = mono_gc_weak_link_get (&mon->data);
+ MonoObject *holder = (MonoObject *)mono_gchandle_get_target ((guint32)mon->data);
if (mon_status_get_owner (mon->status)) {
g_print ("Lock %p in object %p held by thread %d, nest level: %d\n",
mon, holder, mon_status_get_owner (mon->status), mon->nest);
new = NULL;
for (marray = monitor_allocated; marray; marray = marray->next) {
for (i = 0; i < marray->num_monitors; ++i) {
- if (marray->monitors [i].data == NULL) {
+ if (mono_gchandle_get_target ((guint32)marray->monitors [i].data) == NULL) {
new = &marray->monitors [i];
if (new->wait_list) {
/* Orphaned events left by aborted threads */
new->wait_list = g_slist_remove (new->wait_list, new->wait_list->data);
}
}
- mono_gc_weak_link_remove (&new->data, TRUE);
+ mono_gchandle_free ((guint32)new->data);
new->data = monitor_freelist;
monitor_freelist = new;
}
mono_monitor_allocator_lock ();
mon = mon_new (id);
- mono_gc_weak_link_add (&mon->data, obj, TRUE);
+ mon->data = (void *)(size_t)mono_gchandle_new_weakref (obj, TRUE);
mono_monitor_allocator_unlock ();
return mon;
discard_mon (MonoThreadsSync *mon)
{
mono_monitor_allocator_lock ();
- mono_gc_weak_link_remove (&mon->data, TRUE);
+ mono_gchandle_free ((guint32)mon->data);
mon_finalize (mon);
mono_monitor_allocator_unlock ();
}
mono_monitor_exit_flat (obj, lw);
}
-void**
-mono_monitor_get_object_monitor_weak_link (MonoObject *object)
+guint32
+mono_monitor_get_object_monitor_gchandle (MonoObject *object)
{
LockWord lw;
if (lock_word_is_inflated (lw)) {
MonoThreadsSync *mon = lock_word_get_inflated_lock (lw);
- if (mon->data)
- return &mon->data;
+ return (guint32)mon->data;
}
- return NULL;
+ return 0;
}
/*
void mono_monitor_init (void);
void mono_monitor_cleanup (void);
-void** mono_monitor_get_object_monitor_weak_link (MonoObject *object);
+guint32 mono_monitor_get_object_monitor_gchandle (MonoObject *object);
void mono_monitor_threads_sync_members_offset (int *status_offset, int *nest_offset);
#define MONO_THREADS_SYNC_MEMBER_OFFSET(o) ((o)>>8)
}
/* Null weak links to dead objects. */
- sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_NURSERY);
- if (generation == GENERATION_OLD)
- sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_OLD);
+ sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_NURSERY, FALSE);
+ sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_NURSERY, TRUE);
+ if (generation == GENERATION_OLD) {
+ sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_OLD, FALSE);
+ sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_OLD, TRUE);
+ }
sgen_hash_table_clean (&alive_hash);
}
}
static void G_GNUC_UNUSED
-sgen_client_binary_protocol_dislink_update (gpointer link, gpointer obj, gboolean track, gboolean staged)
+sgen_client_binary_protocol_dislink_update (gpointer link, gpointer obj, gboolean track)
{
#ifdef ENABLE_DTRACE
if (MONO_GC_WEAK_UPDATE_ENABLED ()) {
remove = need_remove_object_for_domain (obj, domain);
if (remove && obj->synchronisation) {
- void **dislink = mono_monitor_get_object_monitor_weak_link (obj);
+ guint32 dislink = mono_monitor_get_object_monitor_gchandle (obj);
if (dislink)
- sgen_register_disappearing_link (NULL, dislink, FALSE, TRUE);
+ mono_gchandle_free (dislink);
}
return remove;
to memory returned to the OS.*/
null_ephemerons_for_domain (domain);
- for (i = GENERATION_NURSERY; i < GENERATION_MAX; ++i)
- sgen_null_links_if (object_in_domain_predicate, domain, i);
+ for (i = GENERATION_NURSERY; i < GENERATION_MAX; ++i) {
+ sgen_null_links_if (object_in_domain_predicate, domain, i, FALSE);
+ sgen_null_links_if (object_in_domain_predicate, domain, i, TRUE);
+ }
for (i = GENERATION_NURSERY; i < GENERATION_MAX; ++i)
sgen_remove_finalizers_if (object_in_domain_predicate, domain, i);
void
mono_gc_weak_link_add (void **link_addr, MonoObject *obj, gboolean track)
{
- sgen_register_disappearing_link (obj, link_addr, track, FALSE);
+ binary_protocol_dislink_add ((gpointer)link_addr, obj, track);
+ *link_addr = (void*)HIDE_POINTER (obj);
}
void
mono_gc_weak_link_remove (void **link_addr, gboolean track)
{
- sgen_register_disappearing_link (NULL, link_addr, track, FALSE);
+ binary_protocol_dislink_remove ((gpointer)link_addr, track);
+ *link_addr = NULL;
}
MonoObject*
return sgen_weak_link_get (link_addr);
}
+gboolean
+mono_gc_object_older_than (MonoObject *object, int generation)
+{
+ return generation == GENERATION_NURSERY && !sgen_ptr_in_nursery (object);
+}
+
gboolean
mono_gc_set_allow_synchronous_major (gboolean flag)
{
#include "mono/sgen/sgen-conf.h"
#endif
+#ifndef HIDE_POINTER
+#define HIDE_POINTER(p) ((gpointer)~(size_t)(p))
+#endif
+
+#ifndef REVEAL_POINTER
+#define REVEAL_POINTER(p) ((gpointer)~(size_t)(p))
+#endif
+
+typedef enum {
+ HANDLE_TYPE_MIN = 0,
+ HANDLE_WEAK = HANDLE_TYPE_MIN,
+ HANDLE_WEAK_TRACK,
+ HANDLE_NORMAL,
+ HANDLE_PINNED,
+ HANDLE_TYPE_MAX
+} GCHandleType;
+
+void mono_gchandle_iterate (GCHandleType handle_type, int max_generation, gpointer callback(gpointer *, GCHandleType, gpointer), gpointer user);
+
typedef struct {
guint minor_gc_count;
guint major_gc_count;
#include "mono/sgen/sgen-protocol.h"
#include "mono/sgen/sgen-pointer-queue.h"
#include "mono/sgen/sgen-client.h"
+#include "mono/sgen/gc-internal-agnostic.h"
#include "mono/utils/mono-membar.h"
#define ptr_in_nursery sgen_ptr_in_nursery
return result;
}
-static SgenHashTable minor_disappearing_link_hash = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_DISLINK_TABLE, INTERNAL_MEM_DISLINK, 0, sgen_aligned_addr_hash, NULL);
-static SgenHashTable major_disappearing_link_hash = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_DISLINK_TABLE, INTERNAL_MEM_DISLINK, 0, sgen_aligned_addr_hash, NULL);
-
-static SgenHashTable*
-get_dislink_hash_table (int generation)
-{
- switch (generation) {
- case GENERATION_NURSERY: return &minor_disappearing_link_hash;
- case GENERATION_OLD: return &major_disappearing_link_hash;
- default: g_assert_not_reached ();
- }
-}
-
-/* LOCKING: assumes the GC lock is held */
-static void
-add_or_remove_disappearing_link (GCObject *obj, void **link, int generation)
+/*
+ * Returns whether to remove the link from its hash.
+ */
+static gpointer
+null_link_if_necessary (gpointer *hidden_entry, GCHandleType handle_type, gpointer user)
{
- SgenHashTable *hash_table = get_dislink_hash_table (generation);
-
- if (!obj) {
- if (sgen_hash_table_remove (hash_table, link, NULL)) {
- SGEN_LOG (5, "Removed dislink %p (%d) from %s table",
- link, hash_table->num_entries, sgen_generation_name (generation));
- }
- return;
+ ScanCopyContext *ctx = (ScanCopyContext *)user;
+ gpointer entry = REVEAL_POINTER (*hidden_entry);
+ char *copy = entry;
+ gboolean entry_in_nursery = ptr_in_nursery (entry);
+ if (sgen_get_current_collection_generation () == GENERATION_NURSERY && !entry_in_nursery)
+ return *hidden_entry;
+ /* Clear link if object is ready for finalization. */
+ if (sgen_gc_is_object_ready_for_finalization (entry)) {
+ return NULL;
}
-
- sgen_hash_table_replace (hash_table, link, NULL, NULL);
- SGEN_LOG (5, "Added dislink for object: %p (%s) at %p to %s table",
- obj, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE_UNCHECKED (obj)), link, sgen_generation_name (generation));
+ ctx->ops->copy_or_mark_object ((void **)©, ctx->queue);
+ g_assert (copy);
+ /* Update pointer if it's moved. */
+ binary_protocol_dislink_update (hidden_entry, copy, handle_type == HANDLE_WEAK_TRACK);
+ return HIDE_POINTER (copy);
}
/* LOCKING: requires that the GC lock is held */
void
-sgen_null_link_in_range (int generation, gboolean before_finalization, ScanCopyContext ctx)
+sgen_null_link_in_range (int generation, gboolean before_finalization, ScanCopyContext ctx, gboolean track)
{
- CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object;
- GrayQueue *queue = ctx.queue;
- void **link;
- gpointer dummy G_GNUC_UNUSED;
- SgenHashTable *hash = get_dislink_hash_table (generation);
-
- SGEN_HASH_TABLE_FOREACH (hash, link, dummy) {
- GCObject *object;
- gboolean track;
-
- /*
- We null a weak link before unregistering it, so it's possible that a thread is
- suspended right in between setting the content to null and staging the unregister.
-
- The rest of this code cannot handle null links as DISLINK_OBJECT (NULL) produces an invalid address.
-
- We should simply skip the entry as the staged removal will take place during the next GC.
- */
- if (!*link) {
- SGEN_LOG (5, "Dislink %p was externally nullified", link);
- continue;
- }
+ mono_gchandle_iterate (track ? HANDLE_WEAK_TRACK : HANDLE_WEAK, generation, null_link_if_necessary, &ctx);
+}
- track = DISLINK_TRACK (link);
- /*
- * Tracked references are processed after
- * finalization handling whereas standard weak
- * references are processed before. If an
- * object is still not marked after finalization
- * handling it means that it either doesn't have
- * a finalizer or the finalizer has already run,
- * so we must null a tracking reference.
- */
- if (track != before_finalization) {
- object = DISLINK_OBJECT (link);
- /*
- We should guard against a null object been hidden. This can sometimes happen.
- */
- if (!object) {
- SGEN_LOG (5, "Dislink %p with a hidden null object", link);
- continue;
- }
+typedef struct {
+ SgenObjectPredicateFunc predicate;
+ gpointer data;
+} WeakLinkAlivePredicateClosure;
- if (!major_collector.is_object_live (object)) {
- if (sgen_gc_is_object_ready_for_finalization (object)) {
- *link = NULL;
- binary_protocol_dislink_update (link, NULL, 0, 0);
- SGEN_LOG (5, "Dislink nullified at %p to GCed object %p", link, object);
- SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
- continue;
- } else {
- GCObject *copy = object;
- copy_func (©, queue);
-
- /* Update pointer if it's moved. If the object
- * has been moved out of the nursery, we need to
- * remove the link from the minor hash table to
- * the major one.
- *
- * FIXME: what if an object is moved earlier?
- */
-
- if (hash == &minor_disappearing_link_hash && !ptr_in_nursery (copy)) {
- SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
-
- g_assert (copy);
- *link = HIDE_POINTER (copy, track);
- add_or_remove_disappearing_link (copy, link, GENERATION_OLD);
- binary_protocol_dislink_update (link, copy, track, 0);
-
- SGEN_LOG (5, "Upgraded dislink at %p to major because object %p moved to %p", link, object, copy);
-
- continue;
- } else {
- *link = HIDE_POINTER (copy, track);
- binary_protocol_dislink_update (link, copy, track, 0);
- SGEN_LOG (5, "Updated dislink at %p to %p", link, DISLINK_OBJECT (link));
- }
- }
- }
- }
- } SGEN_HASH_TABLE_FOREACH_END;
+static gpointer
+null_link_if (gpointer *hidden_entry, GCHandleType handle_type, gpointer user)
+{
+ /* Strictly speaking, function pointers are not guaranteed to have the same size as data pointers. */
+ WeakLinkAlivePredicateClosure *closure = (WeakLinkAlivePredicateClosure *)user;
+ gpointer entry = REVEAL_POINTER (*hidden_entry);
+ if (!entry)
+ return NULL;
+ if (closure->predicate ((MonoObject*)entry, closure->data)) {
+ binary_protocol_dislink_update (hidden_entry, NULL, 0);
+ return NULL;
+ }
+ return *hidden_entry;
}
/* LOCKING: requires that the GC lock is held */
void
-sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generation)
+sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generation, gboolean track)
{
- void **link;
- gpointer dummy G_GNUC_UNUSED;
- SgenHashTable *hash = get_dislink_hash_table (generation);
- SGEN_HASH_TABLE_FOREACH (hash, link, dummy) {
- char *object = DISLINK_OBJECT (link);
-
- if (!*link)
- continue;
-
- if (predicate ((GCObject*)object, data)) {
- *link = NULL;
- binary_protocol_dislink_update (link, NULL, 0, 0);
- SGEN_LOG (5, "Dislink nullified by predicate at %p to GCed object %p", link, object);
- SGEN_HASH_TABLE_FOREACH_REMOVE (FALSE /* TRUE */);
- continue;
- }
- } SGEN_HASH_TABLE_FOREACH_END;
+ WeakLinkAlivePredicateClosure closure = { predicate, data };
+ mono_gchandle_iterate (track ? HANDLE_WEAK_TRACK : HANDLE_WEAK, generation, null_link_if, &closure);
}
void
} SGEN_HASH_TABLE_FOREACH_END;
}
-/* LOCKING: requires that the GC lock is held */
-static void
-process_dislink_stage_entry (GCObject *obj, void *_link, int index)
-{
- void **link = _link;
-
- if (index >= 0)
- binary_protocol_dislink_process_staged (link, obj, index);
-
- add_or_remove_disappearing_link (NULL, link, GENERATION_NURSERY);
- add_or_remove_disappearing_link (NULL, link, GENERATION_OLD);
- if (obj) {
- if (ptr_in_nursery (obj))
- add_or_remove_disappearing_link (obj, link, GENERATION_NURSERY);
- else
- add_or_remove_disappearing_link (obj, link, GENERATION_OLD);
- }
-}
-
#define NUM_DISLINK_STAGE_ENTRIES 1024
static volatile gint32 next_dislink_stage_entry = 0;
-static StageEntry dislink_stage_entries [NUM_DISLINK_STAGE_ENTRIES];
/* LOCKING: requires that the GC lock is held */
void
sgen_process_dislink_stage_entries (void)
{
lock_stage_for_processing (&next_dislink_stage_entry);
- process_stage_entries (NUM_DISLINK_STAGE_ENTRIES, &next_dislink_stage_entry, dislink_stage_entries, process_dislink_stage_entry);
-}
-
-void
-sgen_register_disappearing_link (GCObject *obj, void **link, gboolean track, gboolean in_gc)
-{
- if (obj)
- *link = HIDE_POINTER (obj, track);
- else
- *link = NULL;
-
-#if 1
- if (in_gc) {
- binary_protocol_dislink_update (link, obj, track, 0);
- process_dislink_stage_entry (obj, link, -1);
- } else {
- int index;
- binary_protocol_dislink_update (link, obj, track, 1);
- while ((index = add_stage_entry (NUM_DISLINK_STAGE_ENTRIES, &next_dislink_stage_entry, dislink_stage_entries, obj, link)) == -1) {
- if (try_lock_stage_for_processing (NUM_DISLINK_STAGE_ENTRIES, &next_dislink_stage_entry)) {
- LOCK_GC;
- process_stage_entries (NUM_DISLINK_STAGE_ENTRIES, &next_dislink_stage_entry, dislink_stage_entries, process_dislink_stage_entry);
- UNLOCK_GC;
- }
- }
- binary_protocol_dislink_update_staged (link, obj, track, index);
- }
-#else
- if (!in_gc)
- LOCK_GC;
- binary_protocol_dislink_update (link, obj, track, 0);
- process_dislink_stage_entry (obj, link, -1);
- if (!in_gc)
- UNLOCK_GC;
-#endif
}
void
We must clear weak links that don't track resurrection before processing object ready for
finalization so they can be cleared before that.
*/
- sgen_null_link_in_range (generation, TRUE, ctx);
+ sgen_null_link_in_range (generation, TRUE, ctx, FALSE);
if (generation == GENERATION_OLD)
- sgen_null_link_in_range (GENERATION_NURSERY, TRUE, ctx);
+ sgen_null_link_in_range (GENERATION_NURSERY, TRUE, ctx, FALSE);
/* walk the finalization queue and move also the objects that need to be
*/
g_assert (sgen_gray_object_queue_is_empty (queue));
for (;;) {
- sgen_null_link_in_range (generation, FALSE, ctx);
+ sgen_null_link_in_range (generation, FALSE, ctx, TRUE);
if (generation == GENERATION_OLD)
- sgen_null_link_in_range (GENERATION_NURSERY, FALSE, ctx);
+ sgen_null_link_in_range (GENERATION_NURSERY, FALSE, ctx, TRUE);
if (sgen_gray_object_queue_is_empty (queue))
break;
sgen_drain_gray_stack (-1, ctx);
mono_thread_smr_init ();
#endif
- LOCK_INIT (gc_mutex);
+ mono_mutex_init_recursive (&gc_mutex);
gc_debug_file = stderr;
return GPOINTER_TO_UINT (ptr) >> 3;
}
-/*
- * The link pointer is hidden by negating each bit. We use the lowest
- * bit of the link (before negation) to store whether it needs
- * resurrection tracking.
- */
-#define HIDE_POINTER(p,t) ((gpointer)(~((size_t)(p)|((t)?1:0))))
-#define REVEAL_POINTER(p) ((gpointer)((~(size_t)(p))&~3L))
-
#define SGEN_PTR_IN_NURSERY(p,bits,start,end) (((mword)(p) & ~((1 << (bits)) - 1)) == (mword)(start))
#ifdef USER_CONFIG
typedef gboolean (*SgenObjectPredicateFunc) (GCObject *obj, void *user_data);
-void sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generation);
+void sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generation, gboolean track);
gboolean sgen_gc_is_object_ready_for_finalization (GCObject *object);
void sgen_gc_lock (void);
const char* sgen_generation_name (int generation);
void sgen_finalize_in_range (int generation, ScanCopyContext ctx);
-void sgen_null_link_in_range (int generation, gboolean before_finalization, ScanCopyContext ctx);
+void sgen_null_link_in_range (int generation, gboolean before_finalization, ScanCopyContext ctx, gboolean track);
void sgen_process_fin_stage_entries (void);
gboolean sgen_have_pending_finalizers (void);
void sgen_object_register_for_finalization (GCObject *obj, void *user_data);
IS_VTABLE_MATCH (FALSE)
END_PROTOCOL_ENTRY
-BEGIN_PROTOCOL_ENTRY_HEAVY4 (binary_protocol_dislink_update, TYPE_POINTER, link, TYPE_POINTER, obj, TYPE_BOOL, track, TYPE_BOOL, staged)
-CUSTOM_PRINT(entry->obj ? printf ("link %p obj %p staged %d track %d", entry->link, entry->obj, entry->staged, entry->track) : printf ("link %p obj %p staged %d", entry->link, entry->obj, entry->staged))
+BEGIN_PROTOCOL_ENTRY_HEAVY3 (binary_protocol_dislink_add, TYPE_POINTER, link, TYPE_POINTER, obj, TYPE_BOOL, track)
+DEFAULT_PRINT ()
IS_ALWAYS_MATCH (FALSE)
MATCH_INDEX (ptr == entry->link ? 0 : ptr == entry->obj ? 1 : BINARY_PROTOCOL_NO_MATCH)
IS_VTABLE_MATCH (FALSE)
END_PROTOCOL_ENTRY_HEAVY
-BEGIN_PROTOCOL_ENTRY_HEAVY4 (binary_protocol_dislink_update_staged, TYPE_POINTER, link, TYPE_POINTER, obj, TYPE_BOOL, track, TYPE_INT, index)
-CUSTOM_PRINT(entry->obj ? printf ("link %p obj %p index %d track %d", entry->link, entry->obj, entry->index, entry->track) : printf ("link %p obj %p index %d", entry->link, entry->obj, entry->index))
+BEGIN_PROTOCOL_ENTRY_HEAVY3 (binary_protocol_dislink_update, TYPE_POINTER, link, TYPE_POINTER, obj, TYPE_BOOL, track)
+CUSTOM_PRINT(entry->obj ? printf ("link %p obj %p track %d", entry->link, entry->obj, entry->track) : printf ("link %p obj %p", entry->link, entry->obj))
IS_ALWAYS_MATCH (FALSE)
MATCH_INDEX (ptr == entry->link ? 0 : ptr == entry->obj ? 1 : BINARY_PROTOCOL_NO_MATCH)
IS_VTABLE_MATCH (FALSE)
END_PROTOCOL_ENTRY_HEAVY
-BEGIN_PROTOCOL_ENTRY_HEAVY3 (binary_protocol_dislink_process_staged, TYPE_POINTER, link, TYPE_POINTER, obj, TYPE_INT, index)
+BEGIN_PROTOCOL_ENTRY_HEAVY2 (binary_protocol_dislink_remove, TYPE_POINTER, link, TYPE_INT, track)
DEFAULT_PRINT ()
IS_ALWAYS_MATCH (FALSE)
-MATCH_INDEX (ptr == entry->link ? 0 : ptr == entry->obj ? 1 : BINARY_PROTOCOL_NO_MATCH)
+MATCH_INDEX (ptr == entry->link ? 0 : BINARY_PROTOCOL_NO_MATCH)
IS_VTABLE_MATCH (FALSE)
END_PROTOCOL_ENTRY_HEAVY