Skip to content

Commit d88c7ba

Browse files
authored
[mono][interp] Keep delegate alive during invocation (#100832)
When invoking a delegate, we were overwritting the stack slot containing the delegate object reference. In the case of invoking a delegate for a dynamic method, we were running into issues when the delegate object is collected while the method is executed because the method code is also discarded.
1 parent f7f67bb commit d88c7ba

File tree

4 files changed

+24
-0
lines changed

4 files changed

+24
-0
lines changed

src/mono/mono/mini/interp/interp-internals.h

+1
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ struct InterpMethod {
154154
unsigned int hasthis; // boolean
155155
MonoProfilerCallInstrumentationFlags prof_flags;
156156
InterpMethodCodeType code_type;
157+
int ref_slot_offset; // GC visible pointer slot
157158
MonoBitSet *ref_slots;
158159
#ifdef ENABLE_EXPERIMENT_TIERED
159160
MiniTieredCounter tiered_counter;

src/mono/mono/mini/interp/interp.c

+3
Original file line numberDiff line numberDiff line change
@@ -4164,6 +4164,9 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause
41644164
}
41654165
cmethod = del_imethod;
41664166
if (!is_multicast) {
4167+
int ref_slot_offset = frame->imethod->ref_slot_offset;
4168+
if (ref_slot_offset >= 0)
4169+
LOCAL_VAR (ref_slot_offset, gpointer) = del;
41674170
int param_count = ip [4];
41684171
if (cmethod->param_count == param_count + 1) {
41694172
// Target method is static but the delegate has a target object. We handle

src/mono/mono/mini/interp/transform.c

+19
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,15 @@ interp_create_dummy_var (TransformData *td)
451451
td->vars [td->dummy_var].global = TRUE;
452452
}
453453

454+
static void
455+
interp_create_ref_handle_var (TransformData *td)
456+
{
457+
int var = interp_create_var_explicit (td, m_class_get_byval_arg (mono_defaults.int_class), sizeof (gpointer));
458+
td->vars [var].global = TRUE;
459+
interp_alloc_global_var_offset (td, var);
460+
td->ref_handle_var = var;
461+
}
462+
454463
static int
455464
get_tos_offset (TransformData *td)
456465
{
@@ -3756,6 +3765,10 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
37563765
td->last_ins->data [0] = get_data_item_index_imethod (td, mono_interp_get_imethod (target_method));
37573766
} else {
37583767
if (is_delegate_invoke) {
3768+
// MINT_CALL_DELEGATE will store the delegate object into this slot so it is kept alive
3769+
// while the method is invoked
3770+
if (td->ref_handle_var == -1)
3771+
interp_create_ref_handle_var (td);
37593772
interp_add_ins (td, MINT_CALL_DELEGATE);
37603773
interp_ins_set_dreg (td->last_ins, dreg);
37613774
interp_ins_set_sreg (td->last_ins, MINT_CALL_ARGS_SREG);
@@ -9085,6 +9098,7 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG
90859098
td->n_data_items = 0;
90869099
td->max_data_items = 0;
90879100
td->dummy_var = -1;
9101+
td->ref_handle_var = -1;
90889102
td->data_items = NULL;
90899103
td->data_hash = g_hash_table_new (NULL, NULL);
90909104
#ifdef ENABLE_EXPERIMENT_TIERED
@@ -9260,6 +9274,11 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG
92609274
}
92619275
}
92629276

9277+
if (td->ref_handle_var != -1)
9278+
rtm->ref_slot_offset = td->vars [td->ref_handle_var].offset;
9279+
else
9280+
rtm->ref_slot_offset = -1;
9281+
92639282
/* Save debug info */
92649283
interp_save_debug_info (rtm, header, td, td->line_numbers);
92659284

src/mono/mono/mini/interp/transform.h

+1
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ typedef struct
285285
gint32 total_locals_size;
286286
gint32 max_stack_size;
287287
int dummy_var;
288+
int ref_handle_var;
288289
int *local_ref_count;
289290
unsigned int il_locals_offset;
290291
unsigned int il_locals_size;

0 commit comments

Comments
 (0)