From 542bccc2e956760180a396cddaa7bc5f78c2e13e Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Tue, 3 Oct 2023 13:49:28 +0300 Subject: [PATCH 1/3] [mono][interp] Small refactoring to make the code clearer Previous code was checking if we should have already pushed a dreg, to compute the correct position of the argument on the stack. Save pointer to args directly instead. --- src/mono/mono/mini/interp/transform.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index a0e9e5fa2e666..f8e5b8d25c133 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3696,6 +3696,8 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target int call_offset = -1; + StackInfo *sp_args = td->sp; + if (!td->optimized && op == -1) { int param_offset; if (num_args) @@ -3776,9 +3778,9 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target if (num_sregs == 1) interp_ins_set_sreg (td->last_ins, first_sreg); else if (num_sregs == 2) - interp_ins_set_sregs2 (td->last_ins, first_sreg, td->sp [!has_dreg].local); + interp_ins_set_sregs2 (td->last_ins, first_sreg, sp_args [1].local); else if (num_sregs == 3) - interp_ins_set_sregs3 (td->last_ins, first_sreg, td->sp [!has_dreg].local, td->sp [!has_dreg + 1].local); + interp_ins_set_sregs3 (td->last_ins, first_sreg, sp_args [1].local, sp_args [2].local); else g_error ("Unsupported opcode"); } From e3bcb32eaae20cd6962b29e2935ad154285d2198 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Tue, 3 Oct 2023 13:53:29 +0300 Subject: [PATCH 2/3] [mono][interp] Fix calling of static delegates with simd arguments If we do a delegate call that translates to a static call, the delegate pointer that was passed needs to be skipped and we need to pass the actual arguments. However, the following arguments might not come immediately after the delegate pointer, if the first argument is simd aligned. Pass this information to MINT_CALL_DELEGATE so the correct offset of the arguments can be computed. --- src/mono/mono/mini/interp/interp.c | 4 ++-- src/mono/mono/mini/interp/mintops.def | 2 +- src/mono/mono/mini/interp/transform.c | 9 +++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 463c25a7972bd..7734c168345cf 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -4062,10 +4062,10 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause } else { // skip the delegate pointer for static calls // FIXME we could avoid memmove - memmove (locals + call_args_offset, locals + call_args_offset + MINT_STACK_SLOT_SIZE, ip [3]); + memmove (locals + call_args_offset, locals + call_args_offset + ip [5], ip [3]); } } - ip += 5; + ip += 6; InterpMethodCodeType code_type = cmethod->code_type; diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index fe3e5be02f551..7dd9d914fa328 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -688,7 +688,7 @@ OPDEF(MINT_ARRAY_ELEMENT_SIZE, "array_element_size", 3, 1, 1, MintOpNoArgs) /* Calls */ OPDEF(MINT_CALL, "call", 4, 1, 1, MintOpMethodToken) OPDEF(MINT_CALLVIRT_FAST, "callvirt.fast", 5, 1, 1, MintOpMethodToken) -OPDEF(MINT_CALL_DELEGATE, "call.delegate", 5, 1, 1, MintOpTwoShorts) +OPDEF(MINT_CALL_DELEGATE, "call.delegate", 6, 1, 1, MintOpTwoShorts) OPDEF(MINT_CALLI, "calli", 4, 1, 2, MintOpNoArgs) OPDEF(MINT_CALLI_NAT, "calli.nat", 8, 1, 2, MintOpTwoShorts) OPDEF(MINT_CALLI_NAT_DYNAMIC, "calli.nat.dynamic", 5, 1, 2, MintOpShortInt) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index f8e5b8d25c133..33f11d2b58aac 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3801,6 +3801,15 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target interp_ins_set_sreg (td->last_ins, MINT_CALL_ARGS_SREG); td->last_ins->data [0] = GUINT32_TO_UINT16 (params_stack_size); td->last_ins->data [1] = get_data_item_index (td, (void *)csignature); + if (csignature->param_count) { + // Check if the first arg (after the delegate pointer) is simd + // In case the delegate represents static method with no target, the instruction + // needs to be able to access the actual arguments to continue with the call so it + // needs to know whether there is an empty stack slot between the delegate ptr and the + // rest of the args + gboolean first_arg_is_simd = td->locals [sp_args [1].local].flags & INTERP_LOCAL_FLAG_SIMD; + td->last_ins->data [2] = first_arg_is_simd ? MINT_SIMD_ALIGNMENT : MINT_STACK_SLOT_SIZE; + } } else if (calli) { MintICallSig icall_sig = MINT_ICALLSIG_MAX; #ifndef MONO_ARCH_HAS_NO_PROPER_MONOCTX From f6baa58d7b27a016f5a582121fb3a46ccd87400c Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Tue, 3 Oct 2023 13:56:39 +0300 Subject: [PATCH 3/3] [mono][interp] Don't pass csignature to MINT_CALL_DELEGATE Pass param_count directly --- src/mono/mono/mini/interp/interp.c | 4 +--- src/mono/mono/mini/interp/transform.c | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 7734c168345cf..4c4292fbb21e4 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -3996,9 +3996,6 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause MINT_IN_BREAK; } MINT_IN_CASE(MINT_CALL_DELEGATE) { - // FIXME We don't need to encode the whole signature, just param_count - MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [4]]; - int param_count = csignature->param_count; return_offset = ip [1]; call_args_offset = ip [2]; MonoDelegate *del = LOCAL_VAR (call_args_offset, MonoDelegate*); @@ -4044,6 +4041,7 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause } cmethod = del_imethod; if (!is_multicast) { + int param_count = ip [4]; if (cmethod->param_count == param_count + 1) { // Target method is static but the delegate has a target object. We handle // this separately from the case below, because, for these calls, the instance diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 33f11d2b58aac..cb275c7db06d0 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3800,7 +3800,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target interp_ins_set_dreg (td->last_ins, dreg); interp_ins_set_sreg (td->last_ins, MINT_CALL_ARGS_SREG); td->last_ins->data [0] = GUINT32_TO_UINT16 (params_stack_size); - td->last_ins->data [1] = get_data_item_index (td, (void *)csignature); + td->last_ins->data [1] = GUINT32_TO_UINT16 (csignature->param_count); if (csignature->param_count) { // Check if the first arg (after the delegate pointer) is simd // In case the delegate represents static method with no target, the instruction