Skip to content

Commit 5a395ed

Browse files
authored
[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 44ad4db commit 5a395ed

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
@@ -2052,7 +2052,8 @@ emit_delegate_invoke_internal_ilgen (MonoMethodBuilder *mb, MonoMethodSignature
20522052
}
20532053
mono_mb_emit_ldarg_addr (mb, 1);
20542054
mono_mb_emit_ldarg (mb, 0);
2055-
mono_mb_emit_icall (mb, mono_get_addr_compiled_method);
2055+
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2056+
mono_mb_emit_byte (mb, CEE_MONO_LDVIRTFTN_DELEGATE);
20562057
mono_mb_emit_op (mb, CEE_CALLI, target_method_sig);
20572058
} else {
20582059
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
@@ -3863,6 +3863,34 @@ max_d (double lhs, double rhs)
38633863
return fmax (lhs, rhs);
38643864
}
38653865

3866+
// Equivalent of mono_get_addr_compiled_method
3867+
static gpointer
3868+
interp_ldvirtftn_delegate (gpointer arg, MonoDelegate *del)
3869+
{
3870+
MonoMethod *virtual_method = del->method;
3871+
ERROR_DECL(error);
3872+
3873+
MonoClass *klass = del->object.vtable->klass;
3874+
MonoMethod *invoke = mono_get_delegate_invoke_internal (klass);
3875+
MonoMethodSignature *invoke_sig = mono_method_signature_internal (invoke);
3876+
3877+
MonoClass *arg_class = NULL;
3878+
if (m_type_is_byref (invoke_sig->params [0])) {
3879+
arg_class = mono_class_from_mono_type_internal (invoke_sig->params [0]);
3880+
} else {
3881+
MonoObject *object = (MonoObject*)arg;
3882+
arg_class = object->vtable->klass;
3883+
}
3884+
3885+
MonoMethod *res = mono_class_get_virtual_method (arg_class, virtual_method, error);
3886+
mono_error_assert_ok (error);
3887+
3888+
gboolean need_unbox = m_class_is_valuetype (res->klass) && !m_class_is_valuetype (virtual_method->klass);
3889+
3890+
InterpMethod *imethod = mono_interp_get_imethod (res);
3891+
return imethod_to_ftnptr (imethod, need_unbox);
3892+
}
3893+
38663894
/*
38673895
* If CLAUSE_ARGS is non-null, start executing from it.
38683896
* The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
@@ -7794,6 +7822,15 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
77947822
ip += 3;
77957823
MINT_IN_BREAK;
77967824
}
7825+
MINT_IN_CASE(MINT_LDVIRTFTN_DELEGATE) {
7826+
gpointer arg = LOCAL_VAR (ip [2], gpointer);
7827+
MonoDelegate *del = LOCAL_VAR (ip [3], MonoDelegate*);
7828+
NULL_CHECK (arg);
7829+
7830+
LOCAL_VAR (ip [1], gpointer) = interp_ldvirtftn_delegate (arg, del);
7831+
ip += 4;
7832+
MINT_IN_BREAK;
7833+
}
77977834

77987835
#define MATH_UNOP(mathfunc) \
77997836
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
@@ -732,6 +732,7 @@ OPDEF(MINT_SDB_INTR_LOC, "sdb_intr_loc", 1, 0, 0, MintOpNoArgs)
732732
OPDEF(MINT_SDB_SEQ_POINT, "sdb_seq_point", 1, 0, 0, MintOpNoArgs)
733733
OPDEF(MINT_SDB_BREAKPOINT, "sdb_breakpoint", 1, 0, 0, MintOpNoArgs)
734734
OPDEF(MINT_LD_DELEGATE_METHOD_PTR, "ld_delegate_method_ptr", 3, 1, 1, MintOpNoArgs)
735+
OPDEF(MINT_LDVIRTFTN_DELEGATE, "ldvirtftn_delegate", 4, 1, 2, MintOpNoArgs)
735736

736737
// Math intrinsics
737738
// double

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8056,6 +8056,16 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
80568056
push_simple_type (td, STACK_TYPE_I);
80578057
interp_ins_set_dreg (td->last_ins, td->sp [-1].var);
80588058
break;
8059+
case CEE_MONO_LDVIRTFTN_DELEGATE:
8060+
CHECK_STACK (td, 2);
8061+
td->sp -= 2;
8062+
td->ip += 1;
8063+
interp_add_ins (td, MINT_LDVIRTFTN_DELEGATE);
8064+
interp_ins_set_sregs2 (td->last_ins, td->sp [0].var, td->sp [1].var);
8065+
push_simple_type (td, STACK_TYPE_I);
8066+
interp_ins_set_dreg (td->last_ins, td->sp [-1].var);
8067+
break;
8068+
80598069
case CEE_MONO_CALLI_EXTRA_ARG: {
80608070
int saved_local = td->sp [-1].var;
80618071
/* 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
@@ -11594,6 +11594,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
1159411594
*sp++ = ins;
1159511595
break;
1159611596
}
11597+
case MONO_CEE_MONO_LDVIRTFTN_DELEGATE: {
11598+
CHECK_STACK (2);
11599+
sp -= 2;
11600+
11601+
ins = mono_emit_jit_icall (cfg, mono_get_addr_compiled_method, sp);
11602+
*sp++ = ins;
11603+
break;
11604+
}
1159711605
case MONO_CEE_MONO_CALLI_EXTRA_ARG: {
1159811606
MonoInst *addr;
1159911607
MonoInst *arg;

0 commit comments

Comments
 (0)