diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 463c25a7972bd..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 @@ -4062,10 +4060,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 a0e9e5fa2e666..cb275c7db06d0 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"); } @@ -3798,7 +3800,16 @@ 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 + // 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