Skip to content

Commit 881b4bd

Browse files
github-actions[bot]BrzVladsteveisok
authored
[mono][interp] Fix execution of delegate invoke wrapper with interpreter (#111700)
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. Co-authored-by: Vlad Brezae <[email protected]> Co-authored-by: Steve Pfister <[email protected]>
1 parent 120e0b6 commit 881b4bd

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
@@ -3862,6 +3862,34 @@ max_d (double lhs, double rhs)
38623862
return fmax (lhs, rhs);
38633863
}
38643864

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

77947831
#define MATH_UNOP(mathfunc) \
77957832
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
@@ -728,6 +728,7 @@ OPDEF(MINT_SDB_INTR_LOC, "sdb_intr_loc", 1, 0, 0, MintOpNoArgs)
728728
OPDEF(MINT_SDB_SEQ_POINT, "sdb_seq_point", 1, 0, 0, MintOpNoArgs)
729729
OPDEF(MINT_SDB_BREAKPOINT, "sdb_breakpoint", 1, 0, 0, MintOpNoArgs)
730730
OPDEF(MINT_LD_DELEGATE_METHOD_PTR, "ld_delegate_method_ptr", 3, 1, 1, MintOpNoArgs)
731+
OPDEF(MINT_LDVIRTFTN_DELEGATE, "ldvirtftn_delegate", 4, 1, 2, MintOpNoArgs)
731732

732733
// Math intrinsics
733734
// double

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8011,6 +8011,16 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
80118011
push_simple_type (td, STACK_TYPE_I);
80128012
interp_ins_set_dreg (td->last_ins, td->sp [-1].var);
80138013
break;
8014+
case CEE_MONO_LDVIRTFTN_DELEGATE:
8015+
CHECK_STACK (td, 2);
8016+
td->sp -= 2;
8017+
td->ip += 1;
8018+
interp_add_ins (td, MINT_LDVIRTFTN_DELEGATE);
8019+
interp_ins_set_sregs2 (td->last_ins, td->sp [0].var, td->sp [1].var);
8020+
push_simple_type (td, STACK_TYPE_I);
8021+
interp_ins_set_dreg (td->last_ins, td->sp [-1].var);
8022+
break;
8023+
80148024
case CEE_MONO_CALLI_EXTRA_ARG: {
80158025
int saved_local = td->sp [-1].var;
80168026
/* 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
@@ -11597,6 +11597,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
1159711597
*sp++ = ins;
1159811598
break;
1159911599
}
11600+
case MONO_CEE_MONO_LDVIRTFTN_DELEGATE: {
11601+
CHECK_STACK (2);
11602+
sp -= 2;
11603+
11604+
ins = mono_emit_jit_icall (cfg, mono_get_addr_compiled_method, sp);
11605+
*sp++ = ins;
11606+
break;
11607+
}
1160011608
case MONO_CEE_MONO_CALLI_EXTRA_ARG: {
1160111609
MonoInst *addr;
1160211610
MonoInst *arg;

0 commit comments

Comments
 (0)