summaryrefslogtreecommitdiff
path: root/src/vm/callingconvention.h
diff options
context:
space:
mode:
authorAditya Mandaleeka <adityam@microsoft.com>2018-08-07 15:17:52 -0700
committerAditya Mandaleeka <adityam@microsoft.com>2018-08-07 15:17:52 -0700
commit87174a2fdf97938b0ee8d64a0b784f1c01bf2932 (patch)
tree24103edd4c7cabd88cbe6bd127df0de23a30af00 /src/vm/callingconvention.h
parenta113b1c803783c9d64f1f0e946ff9a853e3bc140 (diff)
downloadcoreclr-87174a2fdf97938b0ee8d64a0b784f1c01bf2932.tar.gz
coreclr-87174a2fdf97938b0ee8d64a0b784f1c01bf2932.tar.bz2
coreclr-87174a2fdf97938b0ee8d64a0b784f1c01bf2932.zip
Make VM-side changes for ARM64 Windows calling convention.
Diffstat (limited to 'src/vm/callingconvention.h')
-rw-r--r--src/vm/callingconvention.h64
1 files changed, 59 insertions, 5 deletions
diff --git a/src/vm/callingconvention.h b/src/vm/callingconvention.h
index a0d7bd4fa0..a653d8570f 100644
--- a/src/vm/callingconvention.h
+++ b/src/vm/callingconvention.h
@@ -120,8 +120,9 @@ struct TransitionBlock
INT64 x19, x20, x21, x22, x23, x24, x25, x26, x27, x28;
};
};
- ArgumentRegisters m_argumentRegisters;
TADDR padding; // Keep size of TransitionBlock as multiple of 16-byte. Simplifies code in PROLOG_WITH_TRANSITION_BLOCK
+ INT64 m_x8RetBuffReg;
+ ArgumentRegisters m_argumentRegisters;
#else
PORTABILITY_ASSERT("TransitionBlock");
#endif
@@ -135,9 +136,19 @@ struct TransitionBlock
return offsetof(TransitionBlock, m_ReturnAddress);
}
+#ifdef _TARGET_ARM64_
+ static int GetOffsetOfRetBuffArgReg()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return offsetof(TransitionBlock, m_x8RetBuffReg);
+ }
+#endif
+
static BYTE GetOffsetOfArgs()
{
LIMITED_METHOD_CONTRACT;
+
+ // Offset of the stack args (which are after the TransitionBlock)
return sizeof(TransitionBlock);
}
@@ -491,9 +502,13 @@ public:
// in signatures (this pointer and the like). Whether or not these can be used successfully before all the
// explicit arguments have been scanned is platform dependent.
void GetThisLoc(ArgLocDesc * pLoc) { WRAPPER_NO_CONTRACT; GetSimpleLoc(GetThisOffset(), pLoc); }
- void GetRetBuffArgLoc(ArgLocDesc * pLoc) { WRAPPER_NO_CONTRACT; GetSimpleLoc(GetRetBuffArgOffset(), pLoc); }
void GetParamTypeLoc(ArgLocDesc * pLoc) { WRAPPER_NO_CONTRACT; GetSimpleLoc(GetParamTypeArgOffset(), pLoc); }
void GetVASigCookieLoc(ArgLocDesc * pLoc) { WRAPPER_NO_CONTRACT; GetSimpleLoc(GetVASigCookieOffset(), pLoc); }
+
+#ifndef CALLDESCR_RETBUFFARGREG
+ void GetRetBuffArgLoc(ArgLocDesc * pLoc) { WRAPPER_NO_CONTRACT; GetSimpleLoc(GetRetBuffArgOffset(), pLoc); }
+#endif
+
#endif // !_TARGET_X86_
ArgLocDesc* GetArgLocDescForStructInRegs()
@@ -584,11 +599,17 @@ public:
cSlots = 1;
}
+#ifdef _TARGET_ARM64_
+ // Sanity check to make sure no caller is trying to get an ArgLocDesc that
+ // describes the return buffer reg field that's in the TransitionBlock.
+ _ASSERTE(argOffset != TransitionBlock::GetOffsetOfRetBuffArgReg());
+#endif
+
if (!TransitionBlock::IsStackArgumentOffset(argOffset))
{
pLoc->m_idxGenReg = TransitionBlock::GetArgumentIndexFromOffset(argOffset);
pLoc->m_cGenReg = cSlots;
- }
+ }
else
{
pLoc->m_idxStack = TransitionBlock::GetStackArgumentIndexFromOffset(argOffset);
@@ -709,6 +730,13 @@ protected:
void GetSimpleLoc(int offset, ArgLocDesc * pLoc)
{
WRAPPER_NO_CONTRACT;
+
+#ifdef CALLDESCR_RETBUFFARGREG
+ // Codepaths where this could happen have been removed. If this occurs, something
+ // has been missed and this needs another look.
+ _ASSERTE(offset != TransitionBlock::GetOffsetOfRetBuffArgReg());
+#endif
+
pLoc->Init();
pLoc->m_idxGenReg = TransitionBlock::GetArgumentIndexFromOffset(offset);
pLoc->m_cGenReg = 1;
@@ -747,7 +775,7 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetRetBuffArgOffset()
// x86 is special as always
ret += this->HasThis() ? offsetof(ArgumentRegisters, EDX) : offsetof(ArgumentRegisters, ECX);
#elif _TARGET_ARM64_
- ret += (int) offsetof(ArgumentRegisters, x[8]);
+ ret = TransitionBlock::GetOffsetOfRetBuffArgReg();
#else
if (this->HasThis())
ret += TARGET_POINTER_SIZE;
@@ -929,6 +957,7 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset()
m_dwFlags |= ITERATION_STARTED;
}
+ // We're done going through the args for this MetaSig
if (m_argNum == this->NumFixedArgs())
return TransitionBlock::InvalidOffset;
@@ -1312,15 +1341,40 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset()
}
else
{
+ // Only x0-x7 are valid argument registers (x8 is always the return buffer)
if (m_idxGenReg + cArgSlots <= 8)
{
+ // The entirety of the arg fits in the register slots.
+
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
m_idxGenReg += cArgSlots;
return argOfs;
}
else
{
- m_idxGenReg = 8;
+#ifdef _WIN32
+ if (this->IsVarArg() && m_idxGenReg < 8)
+ {
+ // Address the Windows ARM64 varargs case where an arg is split between regs and stack.
+ // This can happen in the varargs case because the first 64 bytes of the stack are loaded
+ // into x0-x7, and any remaining stack arguments are placed normally.
+ int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
+
+ // Increase m_idxStack to account for the space used for the remainder of the arg after
+ // register slots are filled.
+ m_idxStack += (m_idxGenReg + cArgSlots - 8);
+
+ // We used up the remaining reg slots.
+ m_idxGenReg = 8;
+
+ return argOfs;
+ }
+ else
+#endif
+ {
+ // Don't use reg slots for this. It will be passed purely on the stack arg space.
+ m_idxGenReg = 8;
+ }
}
}