protocol_gchandle_update (int handle_type, gpointer link, gpointer old_value, gpointer new_value)
{
gboolean old = MONO_GC_HANDLE_IS_OBJECT_POINTER (old_value);
- gboolean new = MONO_GC_HANDLE_IS_OBJECT_POINTER (new_value);
+ gboolean new_ = MONO_GC_HANDLE_IS_OBJECT_POINTER (new_value);
gboolean track = handle_type == HANDLE_WEAK_TRACK;
if (!MONO_GC_HANDLE_TYPE_IS_WEAK (handle_type))
return;
- if (!old && new)
+ if (!old && new_)
binary_protocol_dislink_add (link, MONO_GC_REVEAL_POINTER (new_value, TRUE), track);
- else if (old && !new)
+ else if (old && !new_)
binary_protocol_dislink_remove (link, track);
- else if (old && new && old_value != new_value)
+ else if (old && new_ && old_value != new_value)
binary_protocol_dislink_update (link, MONO_GC_REVEAL_POINTER (new_value, TRUE), track);
}
static inline gpointer
try_set_slot (volatile gpointer *slot, GCObject *obj, gpointer old, GCHandleType type)
{
- gpointer new;
+ gpointer new_;
if (obj)
- new = MONO_GC_HANDLE_OBJECT_POINTER (obj, GC_HANDLE_TYPE_IS_WEAK (type));
+ new_ = MONO_GC_HANDLE_OBJECT_POINTER (obj, GC_HANDLE_TYPE_IS_WEAK (type));
else
- new = MONO_GC_HANDLE_METADATA_POINTER (sgen_client_default_metadata (), GC_HANDLE_TYPE_IS_WEAK (type));
- SGEN_ASSERT (0, new, "Why is the occupied bit not set?");
- if (InterlockedCompareExchangePointer (slot, new, old) == old) {
- protocol_gchandle_update (type, (gpointer)slot, old, new);
- return new;
+ new_ = MONO_GC_HANDLE_METADATA_POINTER (sgen_client_default_metadata (), GC_HANDLE_TYPE_IS_WEAK (type));
+ SGEN_ASSERT (0, new_, "Why is the occupied bit not set?");
+ if (InterlockedCompareExchangePointer (slot, new_, old) == old) {
+ protocol_gchandle_update (type, (gpointer)slot, old, new_);
+ return new_;
}
return NULL;
}
volatile gpointer *link_addr = &(handles->entries [bucket] [offset]);
if (MONO_GC_HANDLE_OCCUPIED (*link_addr))
return FALSE;
- return try_set_slot (link_addr, obj, NULL, handles->type) != NULL;
+ return try_set_slot (link_addr, obj, NULL, (GCHandleType)handles->type) != NULL;
}
static HandleData gc_handles [] = {
static HandleData *
gc_handles_for_type (GCHandleType type)
{
- g_assert (type < HANDLE_TYPE_MAX);
- return &gc_handles [type];
+ return type < HANDLE_TYPE_MAX ? &gc_handles [type] : NULL;
}
/* This assumes that the world is stopped. */
const size_t new_bucket_size = sizeof (**handles->entries) * growth;
if (handles->capacity >= new_capacity)
return;
- entries = g_malloc0 (new_bucket_size);
+ entries = (gpointer *)g_malloc0 (new_bucket_size);
if (handles->type == HANDLE_PINNED)
sgen_register_root ((char *)entries, new_bucket_size, SGEN_DESCRIPTOR_NULL, ROOT_TYPE_PINNED, MONO_ROOT_SOURCE_GC_HANDLE, "pinned gc handles");
/* The zeroing of the newly allocated bucket must be complete before storing
goto retry;
}
handles->slot_hint = index;
- bucketize (index, &bucket, &offset);
- if (!try_occupy_slot (handles, bucket, offset, obj, track))
- goto retry;
- /* If a GC happens shortly after a new bucket is allocated, the entire
- * bucket could be scanned even though it's mostly empty. To avoid this, we
- * track the maximum index seen so far, so that we can skip the empty slots.
+
+ /*
+ * If a GC happens shortly after a new bucket is allocated, the entire
+ * bucket could be scanned even though it's mostly empty. To avoid this,
+ * we track the maximum index seen so far, so that we can skip the empty
+ * slots.
+ *
+ * Note that we update `max_index` before we even try occupying the
+ * slot. If we did it the other way around and a GC happened in
+ * between, the GC wouldn't know that the slot was occupied. This is
+ * not a huge deal since `obj` is on the stack and thus pinned anyway,
+ * but hopefully some day it won't be anymore.
*/
do {
max_index = handles->max_index;
if (index <= max_index)
break;
- } while (!InterlockedCompareExchange ((volatile gint32 *)&handles->max_index, index, max_index));
+ } while (InterlockedCompareExchange ((volatile gint32 *)&handles->max_index, index, max_index) != max_index);
+
+ bucketize (index, &bucket, &offset);
+ if (!try_occupy_slot (handles, bucket, offset, obj, track))
+ goto retry;
#ifdef HEAVY_STATISTICS
InterlockedIncrement ((volatile gint32 *)&stat_gc_handles_allocated);
if (stat_gc_handles_allocated > stat_gc_handles_max_allocated)
mono_gchandle_get_target (guint32 gchandle)
{
guint index = MONO_GC_HANDLE_SLOT (gchandle);
- guint type = MONO_GC_HANDLE_TYPE (gchandle);
+ GCHandleType type = MONO_GC_HANDLE_TYPE (gchandle);
HandleData *handles = gc_handles_for_type (type);
+ /* Invalid handles are possible; accessing one should produce NULL. (#34276) */
+ if (!handles)
+ return NULL;
guint bucket, offset;
g_assert (index < handles->capacity);
bucketize (index, &bucket, &offset);
sgen_gchandle_set_target (guint32 gchandle, GCObject *obj)
{
guint index = MONO_GC_HANDLE_SLOT (gchandle);
- guint type = MONO_GC_HANDLE_TYPE (gchandle);
+ GCHandleType type = MONO_GC_HANDLE_TYPE (gchandle);
HandleData *handles = gc_handles_for_type (type);
+ if (!handles)
+ return;
guint bucket, offset;
gpointer slot;
do {
slot = handles->entries [bucket] [offset];
SGEN_ASSERT (0, MONO_GC_HANDLE_OCCUPIED (slot), "Why are we setting the target on an unoccupied slot?");
- } while (!try_set_slot (&handles->entries [bucket] [offset], obj, slot, handles->type));
+ } while (!try_set_slot (&handles->entries [bucket] [offset], obj, slot, (GCHandleType)handles->type));
}
static gpointer
if (!MONO_GC_HANDLE_OCCUPIED (slot))
return NULL;
if (MONO_GC_HANDLE_IS_OBJECT_POINTER (slot)) {
- GCObject *obj = MONO_GC_REVEAL_POINTER (slot, is_weak);
+ GCObject *obj = (GCObject *)MONO_GC_REVEAL_POINTER (slot, is_weak);
/* See note [dummy use]. */
sgen_dummy_use (obj);
/*
sgen_gchandle_get_metadata (guint32 gchandle)
{
guint index = MONO_GC_HANDLE_SLOT (gchandle);
- guint type = MONO_GC_HANDLE_TYPE (gchandle);
+ GCHandleType type = MONO_GC_HANDLE_TYPE (gchandle);
HandleData *handles = gc_handles_for_type (type);
+ if (!handles)
+ return NULL;
guint bucket, offset;
if (index >= handles->capacity)
return NULL;
mono_gchandle_free (guint32 gchandle)
{
guint index = MONO_GC_HANDLE_SLOT (gchandle);
- guint type = MONO_GC_HANDLE_TYPE (gchandle);
+ GCHandleType type = MONO_GC_HANDLE_TYPE (gchandle);
HandleData *handles = gc_handles_for_type (type);
+ if (!handles)
+ return;
guint bucket, offset;
gpointer slot;
bucketize (index, &bucket, &offset);
if (!MONO_GC_HANDLE_VALID (hidden))
return hidden;
- obj = MONO_GC_REVEAL_POINTER (hidden, MONO_GC_HANDLE_TYPE_IS_WEAK (handle_type));
+ obj = (GCObject *)MONO_GC_REVEAL_POINTER (hidden, MONO_GC_HANDLE_TYPE_IS_WEAK (handle_type));
SGEN_ASSERT (0, obj, "Why is the hidden pointer NULL?");
if (object_older_than (obj, max_generation))
if (!MONO_GC_HANDLE_VALID (hidden))
return hidden;
- obj = MONO_GC_REVEAL_POINTER (hidden, MONO_GC_HANDLE_TYPE_IS_WEAK (handle_type));
+ obj = (GCObject *)MONO_GC_REVEAL_POINTER (hidden, MONO_GC_HANDLE_TYPE_IS_WEAK (handle_type));
SGEN_ASSERT (0, obj, "Why is the hidden pointer NULL?");
if (object_older_than (obj, max_generation))