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_new_weakref:
* @obj: managed object to get a handle for
- * @pinned: whether the object should be pinned
+ * @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.
* garbage collector. In this case the value of the GCHandle will be
* set to zero.
*
- * If @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.
+ * If @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
+ * 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
* unmanaged code.
* mono_gchandle_get_target:
* @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 `mono_gchandle_new` or
+ * `mono_gchandle_new_weakref`.
*
- * Returns a pointer to the MonoObject represented by the handle or
+ * Returns a pointer to the `MonoObject*` represented by the handle or
* NULL for a collected object if using a weakref handle.
*/
GCObject*
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))