Skip to content

Commit 5e902bc

Browse files
committed
[mono][interp] Fix execution of delegate invoke wrapper with interpreter (#111310)
The wrapper was relatively recently changed to icall into mono_get_addr_compiled_method in order to obtain a native function pointer to call using calli. This is incorrect on interpreter where we expect an `InterpMethod*`. This commit adds a new opcode instead, that on jit it goes through the same icall path, while on interpeter in similarly computes the appropiate method to call. On a separate track, it might be useful to investigate whether the necessary delegate invoke wrapper should have been present in the aot image and not be executed with the interpreter in the first place.
1 parent 2f4a700 commit 5e902bc

File tree

6 files changed

+60
-1
lines changed

6 files changed

+60
-1
lines changed

src/mono/mono/cil/opcode.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ OPDEF(CEE_MONO_GET_SP, "mono_get_sp", Pop0, PushI, InlineNone, 0, 2, 0xF0, 0x20,
328328
OPDEF(CEE_MONO_METHODCONST, "mono_methodconst", Pop0, PushI, InlineI, 0, 2, 0xF0, 0x21, NEXT)
329329
OPDEF(CEE_MONO_PINVOKE_ADDR_CACHE, "mono_pinvoke_addr_cache", Pop0, PushI, InlineI, 0, 2, 0xF0, 0x22, NEXT)
330330
OPDEF(CEE_MONO_REMAP_OVF_EXC, "mono_remap_ovf_exc", Pop0, Push0, InlineI, 0, 2, 0xF0, 0x23, NEXT)
331+
OPDEF(CEE_MONO_LDVIRTFTN_DELEGATE, "mono_ldvirtftn_delegate", PopI+PopI, PushI, InlineNone, 0, 2, 0xF0, 0x24, NEXT)
332+
331333
#ifndef OPALIAS
332334
#define _MONO_CIL_OPALIAS_DEFINED_
333335
#define OPALIAS(a,s,r)

src/mono/mono/metadata/marshal-lightweight.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2102,7 +2102,8 @@ emit_delegate_invoke_internal_ilgen (MonoMethodBuilder *mb, MonoMethodSignature
21022102
else
21032103
mono_mb_emit_ldarg (mb, 1);
21042104
mono_mb_emit_ldarg (mb, 0);
2105-
mono_mb_emit_icall (mb, mono_get_addr_compiled_method);
2105+
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2106+
mono_mb_emit_byte (mb, CEE_MONO_LDVIRTFTN_DELEGATE);
21062107
mono_mb_emit_op (mb, CEE_CALLI, target_method_sig);
21072108
} else {
21082109
mono_mb_emit_byte (mb, CEE_LDNULL);

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3744,6 +3744,34 @@ max_d (double lhs, double rhs)
37443744
static JiterpreterCallInfo jiterpreter_call_info = { 0 };
37453745
#endif
37463746

3747+
// Equivalent of mono_get_addr_compiled_method
3748+
static gpointer
3749+
interp_ldvirtftn_delegate (gpointer arg, MonoDelegate *del)
3750+
{
3751+
MonoMethod *virtual_method = del->method;
3752+
ERROR_DECL(error);
3753+
3754+
MonoClass *klass = del->object.vtable->klass;
3755+
MonoMethod *invoke = mono_get_delegate_invoke_internal (klass);
3756+
MonoMethodSignature *invoke_sig = mono_method_signature_internal (invoke);
3757+
3758+
MonoClass *arg_class = NULL;
3759+
if (m_type_is_byref (invoke_sig->params [0])) {
3760+
arg_class = mono_class_from_mono_type_internal (invoke_sig->params [0]);
3761+
} else {
3762+
MonoObject *object = (MonoObject*)arg;
3763+
arg_class = object->vtable->klass;
3764+
}
3765+
3766+
MonoMethod *res = mono_class_get_virtual_method (arg_class, virtual_method, error);
3767+
mono_error_assert_ok (error);
3768+
3769+
gboolean need_unbox = m_class_is_valuetype (res->klass) && !m_class_is_valuetype (virtual_method->klass);
3770+
3771+
InterpMethod *imethod = mono_interp_get_imethod (res);
3772+
return imethod_to_ftnptr (imethod, need_unbox);
3773+
}
3774+
37473775
/*
37483776
* If CLAUSE_ARGS is non-null, start executing from it.
37493777
* The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
@@ -7566,6 +7594,15 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
75667594
ip += 3;
75677595
MINT_IN_BREAK;
75687596
}
7597+
MINT_IN_CASE(MINT_LDVIRTFTN_DELEGATE) {
7598+
gpointer arg = LOCAL_VAR (ip [2], gpointer);
7599+
MonoDelegate *del = LOCAL_VAR (ip [3], MonoDelegate*);
7600+
NULL_CHECK (arg);
7601+
7602+
LOCAL_VAR (ip [1], gpointer) = interp_ldvirtftn_delegate (arg, del);
7603+
ip += 4;
7604+
MINT_IN_BREAK;
7605+
}
75697606

75707607
#define MATH_UNOP(mathfunc) \
75717608
LOCAL_VAR (ip [1], double) = mathfunc (LOCAL_VAR (ip [2], double)); \

src/mono/mono/mini/interp/mintops.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,7 @@ OPDEF(MINT_SDB_INTR_LOC, "sdb_intr_loc", 1, 0, 0, MintOpNoArgs)
716716
OPDEF(MINT_SDB_SEQ_POINT, "sdb_seq_point", 1, 0, 0, MintOpNoArgs)
717717
OPDEF(MINT_SDB_BREAKPOINT, "sdb_breakpoint", 1, 0, 0, MintOpNoArgs)
718718
OPDEF(MINT_LD_DELEGATE_METHOD_PTR, "ld_delegate_method_ptr", 3, 1, 1, MintOpNoArgs)
719+
OPDEF(MINT_LDVIRTFTN_DELEGATE, "ldvirtftn_delegate", 4, 1, 2, MintOpNoArgs)
719720

720721
// Math intrinsics
721722
// double

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7604,6 +7604,16 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
76047604
push_simple_type (td, STACK_TYPE_I);
76057605
interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
76067606
break;
7607+
case CEE_MONO_LDVIRTFTN_DELEGATE:
7608+
CHECK_STACK (td, 2);
7609+
td->sp -= 2;
7610+
td->ip += 1;
7611+
interp_add_ins (td, MINT_LDVIRTFTN_DELEGATE);
7612+
interp_ins_set_sregs2 (td->last_ins, td->sp [0].var, td->sp [1].var);
7613+
push_simple_type (td, STACK_TYPE_I);
7614+
interp_ins_set_dreg (td->last_ins, td->sp [-1].var);
7615+
break;
7616+
76077617
case CEE_MONO_CALLI_EXTRA_ARG: {
76087618
int saved_local = td->sp [-1].local;
76097619
/* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */

src/mono/mono/mini/method-to-ir.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11342,6 +11342,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
1134211342
*sp++ = ins;
1134311343
break;
1134411344
}
11345+
case MONO_CEE_MONO_LDVIRTFTN_DELEGATE: {
11346+
CHECK_STACK (2);
11347+
sp -= 2;
11348+
11349+
ins = mono_emit_jit_icall (cfg, mono_get_addr_compiled_method, sp);
11350+
*sp++ = ins;
11351+
break;
11352+
}
1134511353
case MONO_CEE_MONO_CALLI_EXTRA_ARG: {
1134611354
MonoInst *addr;
1134711355
MonoInst *arg;

0 commit comments

Comments
 (0)