From d8b910b9feda5acd2f52a317375406604e461430 Mon Sep 17 00:00:00 2001 From: Xu Liangyu Date: Thu, 22 Aug 2024 05:52:46 +0800 Subject: [PATCH] [LoongArch64] ELT profiler: fix reconstruction of struct args passed partially on the stack. (#106747) * Fix the `DoubleManyMixedStructFunc` case in slowpatheltenter.sh. --- src/coreclr/vm/loongarch64/profiler.cpp | 32 +++++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/coreclr/vm/loongarch64/profiler.cpp b/src/coreclr/vm/loongarch64/profiler.cpp index 8da4c3d5137c0..0d926a88f9660 100644 --- a/src/coreclr/vm/loongarch64/profiler.cpp +++ b/src/coreclr/vm/loongarch64/profiler.cpp @@ -119,10 +119,12 @@ LPVOID ProfileArgIterator::GetNextArgAddr() } LPVOID pArg = nullptr; + int argSize = m_argIterator.IsArgPassedByRef() ? (int)sizeof(void*) : m_argIterator.GetArgSize(); if (TransitionBlock::IsFloatArgumentRegisterOffset(argOffset)) { - pArg = (LPBYTE)&pData->floatArgumentRegisters + (argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters()); + int offset = argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters(); + pArg = (LPBYTE)&pData->floatArgumentRegisters + offset; ArgLocDesc* pArgLocDesc = m_argIterator.GetArgLocDescForStructInRegs(); @@ -147,16 +149,18 @@ LPVOID ProfileArgIterator::GetNextArgAddr() } return (LPBYTE)&pData->buffer[bufferPos]; } - _ASSERTE(pArgLocDesc->m_cFloatReg == 2); } + _ASSERTE(offset + argSize <= sizeof(pData->floatArgumentRegisters)); + return pArg; } if (TransitionBlock::IsArgumentRegisterOffset(argOffset)) { - pArg = (LPBYTE)&pData->argumentRegisters + (argOffset - TransitionBlock::GetOffsetOfArgumentRegisters()); + int offset = argOffset - TransitionBlock::GetOffsetOfArgumentRegisters(); + pArg = (LPBYTE)&pData->argumentRegisters + offset; ArgLocDesc* pArgLocDesc = m_argIterator.GetArgLocDescForStructInRegs(); if (pArgLocDesc) @@ -175,14 +179,32 @@ LPVOID ProfileArgIterator::GetNextArgAddr() return (LPBYTE)&pData->buffer[bufferPos]; } - _ASSERTE(pArgLocDesc->m_cFloatReg == 0); } + + if (offset + argSize > (int)sizeof(pData->argumentRegisters)) + { + // Struct partially spilled on stack. + // The first part of struct must be in last argument register. + const int regIndex = NUM_ARGUMENT_REGISTERS - 1; + _ASSERTE(regIndex == offset / sizeof(pData->argumentRegisters.a[0])); + _ASSERTE(argSize <= 16); + _ASSERTE(m_bufferPos + 16 <= sizeof(pData->buffer)); + + UINT32 bufferPos = m_bufferPos; + UINT64* dst = (UINT64*)&pData->buffer[bufferPos]; + m_bufferPos += 16; + + *dst = *(UINT64*)pArg; + // spilled part must be first on stack (if we copy too much, that's ok) + *(dst + 1) = *(UINT64*)pData->profiledSp; + + return (LPBYTE)&pData->buffer[bufferPos]; + } } else { _ASSERTE(TransitionBlock::IsStackArgumentOffset(argOffset)); - pArg = (LPBYTE)pData->profiledSp + (argOffset - TransitionBlock::GetOffsetOfArgs()); }