Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4528,15 +4528,20 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
}
else if (opcode == INTOP_CALLDELEGATE)
{
int32_t firstTargetArgOffset = INTERP_STACK_SLOT_SIZE;
if (numArgs > 1)
int32_t sizeOfArgsUpto16ByteAlignment = 0;
for (int argIndex = 1; argIndex < numArgs; argIndex++)
{
// The first argument is the delegate obj, the second is the first target arg
// The offset of the first target arg relative to the start of delegate call args is equal to the alignment of the
// first target arg.
GetInterpTypeStackSize(m_pVars[callArgs[1]].clsHnd, m_pVars[callArgs[1]].interpType, &firstTargetArgOffset);
int32_t argAlignment = INTERP_STACK_SLOT_SIZE;
int32_t size = GetInterpTypeStackSize(m_pVars[callArgs[argIndex]].clsHnd, m_pVars[callArgs[argIndex]].interpType, &argAlignment);
size = ALIGN_UP_TO(size, INTERP_STACK_SLOT_SIZE);
if (argAlignment == INTERP_STACK_ALIGNMENT)
{
break;
}
sizeOfArgsUpto16ByteAlignment += size;
}
m_pLastNewIns->data[1] = firstTargetArgOffset;

m_pLastNewIns->data[1] = sizeOfArgsUpto16ByteAlignment;
}
}
break;
Expand Down
22 changes: 18 additions & 4 deletions src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2564,10 +2564,10 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
int8_t* returnValueAddress = LOCAL_VAR_ADDR(returnOffset, int8_t);

// Used only for INTOP_CALLDELEGATE to allow removal of the delegate object from the argument list
size_t firstTargetArgOffset = 0;
int32_t sizeOfArgsUpto16ByteAlignment = 0;
if (*ip == INTOP_CALLDELEGATE)
{
firstTargetArgOffset = (size_t)ip[4];
sizeOfArgsUpto16ByteAlignment = ip[4];
ip += 5;
}
else
Expand Down Expand Up @@ -2633,8 +2633,22 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
}
else
{
// Shift args down by one slot to remove the delegate obj pointer
memmove(LOCAL_VAR_ADDR(callArgsOffset, int8_t), LOCAL_VAR_ADDR(callArgsOffset + firstTargetArgOffset, int8_t), pTargetMethod->argsSize);
// Shift args down by one slot to remove the delegate obj pointer.
// We need to preserve alignment of arguments that require 16-byte alignment.
// The sizeOfArgsUpto16ByteAlignment is the size of all the target method args starting at the first argument up to (but not including) the first argument that requires 16-byte alignment.
if (sizeOfArgsUpto16ByteAlignment != 0)
{
memmove(LOCAL_VAR_ADDR(callArgsOffset, int8_t), LOCAL_VAR_ADDR(callArgsOffset + INTERP_STACK_SLOT_SIZE, int8_t), sizeOfArgsUpto16ByteAlignment);
}

if (sizeOfArgsUpto16ByteAlignment != pTargetMethod->argsSize)
{
// There are arguments that require 16-byte alignment
size_t firstAlignedTargetArgDstOffset = ALIGN_UP(sizeOfArgsUpto16ByteAlignment, INTERP_STACK_ALIGNMENT);
size_t firstAlignedTargetArgSrcOffset = ALIGN_UP(INTERP_STACK_SLOT_SIZE + sizeOfArgsUpto16ByteAlignment, INTERP_STACK_ALIGNMENT);
memmove(LOCAL_VAR_ADDR(callArgsOffset + firstAlignedTargetArgDstOffset, int8_t), LOCAL_VAR_ADDR(callArgsOffset + firstAlignedTargetArgSrcOffset, int8_t), pTargetMethod->argsSize - sizeOfArgsUpto16ByteAlignment);
}

// Allocate child frame.
InterpMethodContextFrame *pChildFrame = pFrame->pNext;
if (!pChildFrame)
Expand Down
Loading