diff --git a/src/coreclr/vm/riscv64/profiler.cpp b/src/coreclr/vm/riscv64/profiler.cpp index d3e05ccd867ff9..1cff4dfaa45e1d 100644 --- a/src/coreclr/vm/riscv64/profiler.cpp +++ b/src/coreclr/vm/riscv64/profiler.cpp @@ -174,7 +174,6 @@ LPVOID ProfileArgIterator::GetNextArgAddr() } int argOffset = m_argIterator.GetNextOffset(); - if (argOffset == TransitionBlock::InvalidOffset) { return nullptr; @@ -192,21 +191,39 @@ LPVOID ProfileArgIterator::GetNextArgAddr() } } + int argSize = m_argIterator.IsArgPassedByRef() ? sizeof(void*) : m_argIterator.GetArgSize(); if (TransitionBlock::IsFloatArgumentRegisterOffset(argOffset)) { - return (LPBYTE)&pData->floatArgumentRegisters + (argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters()); + int offset = argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters(); + _ASSERTE(offset + argSize <= sizeof(pData->floatArgumentRegisters)); + return (LPBYTE)&pData->floatArgumentRegisters + offset; } LPVOID pArg = nullptr; if (TransitionBlock::IsArgumentRegisterOffset(argOffset)) { - pArg = (LPBYTE)&pData->argumentRegisters + (argOffset - TransitionBlock::GetOffsetOfArgumentRegisters()); + int offset = argOffset - TransitionBlock::GetOffsetOfArgumentRegisters(); + if (offset + argSize > sizeof(pData->argumentRegisters)) + { + // Struct partially spilled on stack + const int regIndex = NUM_ARGUMENT_REGISTERS - 1; // first part of struct must be in last register + _ASSERTE(regIndex == offset / sizeof(pData->argumentRegisters.a[0])); + const int neededSpace = 2 * sizeof(INT64); + _ASSERTE(argSize <= neededSpace); + _ASSERTE(m_bufferPos + neededSpace <= sizeof(pData->buffer)); + INT64* dest = (INT64*)&pData->buffer[m_bufferPos]; + dest[0] = pData->argumentRegisters.a[regIndex]; + // spilled part must be first on stack (if we copy too much, that's ok) + dest[1] = *(INT64*)pData->profiledSp; + m_bufferPos += neededSpace; + return dest; + } + pArg = (LPBYTE)&pData->argumentRegisters + offset; } else { _ASSERTE(TransitionBlock::IsStackArgumentOffset(argOffset)); - pArg = (LPBYTE)pData->profiledSp + (argOffset - TransitionBlock::GetOffsetOfArgs()); } diff --git a/src/tests/profiler/elt/slowpathcommon.cs b/src/tests/profiler/elt/slowpathcommon.cs index 72e79314faa10d..5d6196ddf44298 100644 --- a/src/tests/profiler/elt/slowpathcommon.cs +++ b/src/tests/profiler/elt/slowpathcommon.cs @@ -369,6 +369,8 @@ public static int RunTest() Console.WriteLine($"DoubleRetFunc returned {DoubleRetFunc()}"); + Console.WriteLine($"FloatRetFunc returned {FloatRetFunc()}"); + Console.WriteLine($"IntegerSseStructFunc returned {IntegerSseStructFunc()}"); Console.WriteLine($"SseIntegerStructFunc returned {SseIntegerStructFunc()}"); @@ -379,6 +381,19 @@ public static int RunTest() Console.WriteLine($"MixedMixedStructFunc returned {MixedMixedStructFunc()}"); + var s1 = new MixedStruct(1, 1); + var s2 = new MixedStruct(2, 2); + var s3 = new MixedStruct(3, 3); + var s4 = new MixedStruct(4, 4); + var s5 = new MixedStruct(5, 5); + var s6 = new MixedStruct(6, 6); + var s7 = new MixedStruct(7, 7); + var s8 = new MixedStruct(8, 8); + var s9 = new MixedStruct(9, 9); + Console.WriteLine($"IntManyMixedStructFunc returned {IntManyMixedStructFunc(11, s1, s2, s3, s4, s5, s6, s7, s8, s9)}"); + + Console.WriteLine($"DoubleManyMixedStructFunc returned {DoubleManyMixedStructFunc(11.0, s1, s2, s3, s4, s5, s6, s7, s8, s9)}"); + return 100; } @@ -519,6 +534,12 @@ public static double DoubleRetFunc() return 13.0; } + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static float FloatRetFunc() + { + return 13.0f; + } + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static IntegerSseStruct IntegerSseStructFunc() { @@ -548,5 +569,19 @@ public static MixedMixedStruct MixedMixedStructFunc() { return new MixedMixedStruct(1.2f, 3, 5, 6.7f); } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static MixedStruct IntManyMixedStructFunc(int i, MixedStruct s1, MixedStruct s2, MixedStruct s3, MixedStruct s4, MixedStruct s5, MixedStruct s6, MixedStruct s7, MixedStruct s8, MixedStruct s9) + { + Console.WriteLine($"i={i} s1=({s1}) s2=({s2}) s3=({s3}) s4=({s4}) s5=({s5}) s6=({s6}) s7=({s7}) s8=({s8}) s9=({s9})"); + return s1; + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static MixedStruct DoubleManyMixedStructFunc(double d, MixedStruct s1, MixedStruct s2, MixedStruct s3, MixedStruct s4, MixedStruct s5, MixedStruct s6, MixedStruct s7, MixedStruct s8, MixedStruct s9) + { + Console.WriteLine($"d={d} s1=({s1}) s2=({s2}) s3=({s3}) s4=({s4}) s5=({s5}) s6=({s6}) s7=({s7}) s8=({s8}) s9=({s9})"); + return s1; + } } } diff --git a/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.cpp b/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.cpp index 7d1f56e40a0985..513195a1305334 100644 --- a/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.cpp +++ b/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.cpp @@ -377,7 +377,48 @@ HRESULT STDMETHODCALLTYPE SlowPathELTProfiler::EnterCallback(FunctionIDOrClientI _sawFuncEnter[functionName.ToWString()] = true; } + else if (functionName == WCHAR("IntManyMixedStructFunc")) + { + int i = 11; + MixedStruct ss[] = {{1, 1.0}, {2, 2.0}, {3, 3.0}, {4, 4.0}, {5, 5.0}, {6, 6.0}, {7, 7.0}, {8, 8.0}, {9, 9.0}}; + vector expectedValues = { + { sizeof(int), (void *)&i, [&](UINT_PTR ptr){ return ValidateInt(ptr, i); } }, + { sizeof(MixedStruct), (void *)&ss[0], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[0]); } }, + { sizeof(MixedStruct), (void *)&ss[1], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[1]); } }, + { sizeof(MixedStruct), (void *)&ss[2], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[2]); } }, + { sizeof(MixedStruct), (void *)&ss[3], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[3]); } }, + { sizeof(MixedStruct), (void *)&ss[4], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[4]); } }, + { sizeof(MixedStruct), (void *)&ss[5], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[5]); } }, + { sizeof(MixedStruct), (void *)&ss[6], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[6]); } }, + { sizeof(MixedStruct), (void *)&ss[7], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[7]); } }, + { sizeof(MixedStruct), (void *)&ss[8], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[8]); } }, + }; + + hr = ValidateFunctionArgs(pArgumentInfo, functionName, expectedValues); + _sawFuncEnter[functionName.ToWString()] = true; + } + else if (functionName == WCHAR("DoubleManyMixedStructFunc")) + { + double d = 11.0; + MixedStruct ss[] = {{1, 1.0}, {2, 2.0}, {3, 3.0}, {4, 4.0}, {5, 5.0}, {6, 6.0}, {7, 7.0}, {8, 8.0}, {9, 9.0}}; + vector expectedValues = { + { sizeof(double), (void *)&d, [&](UINT_PTR ptr){ return ValidateDouble(ptr, d); } }, + { sizeof(MixedStruct), (void *)&ss[0], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[0]); } }, + { sizeof(MixedStruct), (void *)&ss[1], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[1]); } }, + { sizeof(MixedStruct), (void *)&ss[2], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[2]); } }, + { sizeof(MixedStruct), (void *)&ss[3], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[3]); } }, + { sizeof(MixedStruct), (void *)&ss[4], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[4]); } }, + { sizeof(MixedStruct), (void *)&ss[5], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[5]); } }, + { sizeof(MixedStruct), (void *)&ss[6], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[6]); } }, + { sizeof(MixedStruct), (void *)&ss[7], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[7]); } }, + { sizeof(MixedStruct), (void *)&ss[8], [&](UINT_PTR ptr){ return ValidateMixedStruct(ptr, ss[8]); } }, + }; + + hr = ValidateFunctionArgs(pArgumentInfo, functionName, expectedValues); + + _sawFuncEnter[functionName.ToWString()] = true; + } return hr; } @@ -489,6 +530,14 @@ HRESULT STDMETHODCALLTYPE SlowPathELTProfiler::LeaveCallback(FunctionIDOrClientI _sawFuncLeave[functionName.ToWString()] = true; } + else if (functionName == WCHAR("FloatRetFunc")) + { + float f = 13.0f; + ExpectedArgValue floatRetValue = { sizeof(float), (void *)&f, [&](UINT_PTR ptr){ return ValidateFloat(ptr, f); } }; + hr = ValidateOneArgument(pRetvalRange, functionName, 0, floatRetValue); + + _sawFuncLeave[functionName.ToWString()] = true; + } else if (functionName == WCHAR("IntegerSseStructFunc")) { IntegerSseStruct val = { 1, 2, 3.5 }; diff --git a/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.h b/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.h index 1a9a476674750b..dbf0759117664b 100644 --- a/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.h +++ b/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.h @@ -146,6 +146,8 @@ class SlowPathELTProfiler : public Profiler _sawFuncEnter[L"Fp64x3StructDoubleFp64x3StructDoubleFunc"] = false; _sawFuncEnter[L"Fp64x4StructFunc"] = false; _sawFuncEnter[L"Fp64x4StructFp64x4StructFunc"] = false; + _sawFuncEnter[L"IntManyMixedStructFunc"] = false; + _sawFuncEnter[L"DoubleManyMixedStructFunc"] = false; _sawFuncLeave[L"SimpleArgsFunc"] = false; _sawFuncLeave[L"MixedStructFunc"] = false; @@ -158,6 +160,7 @@ class SlowPathELTProfiler : public Profiler _sawFuncLeave[L"Fp64x3StructFunc"] = false; _sawFuncLeave[L"Fp64x4StructFunc"] = false; _sawFuncLeave[L"DoubleRetFunc"] = false; + _sawFuncLeave[L"FloatRetFunc"] = false; _sawFuncLeave[L"IntegerSseStructFunc"] = false; _sawFuncLeave[L"SseIntegerStructFunc"] = false; _sawFuncLeave[L"MixedSseStructFunc"] = false;