Skip to content

Commit 113198b

Browse files
authored
JIT: Fix SysV first/second return register GC info mismatch when generating calls (dotnet#115827)
On SysV it is possible to have mixed SIMD/integer return registers for calls. This leads to a case where the first return register is a SIMD register, while the second return register is an integer register. In that particular case, the emitter would get confused and expect GC information for the second return register to refer to `rdx`, when in reality it refers to `rax`. Fix the problem by detecting the case where the second register is `rax`, and communicating the right information back to the emitter. Also add a test case that reliably segfaults under `DOTNET_GCStress=C` without the fix.
1 parent c9e01a5 commit 113198b

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

src/coreclr/jit/codegenxarch.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6293,6 +6293,18 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA
62936293
{
62946294
params.retSize = emitTypeSize(retTypeDesc->GetReturnRegType(0));
62956295
params.secondRetSize = emitTypeSize(retTypeDesc->GetReturnRegType(1));
6296+
6297+
if (retTypeDesc->GetABIReturnReg(1, call->GetUnmanagedCallConv()) == REG_INTRET)
6298+
{
6299+
// If the second return register is REG_INTRET, then the first
6300+
// return is expected to be in a SIMD register.
6301+
// The emitter has hardcoded belief that params.retSize corresponds to
6302+
// REG_INTRET and secondRetSize to REG_INTRET_1, so fix up the
6303+
// situation here.
6304+
assert(!EA_IS_GCREF_OR_BYREF(params.retSize));
6305+
params.retSize = params.secondRetSize;
6306+
params.secondRetSize = EA_UNKNOWN;
6307+
}
62966308
}
62976309
else
62986310
{
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Threading;
5+
using System.Collections.Generic;
6+
using System.Runtime.CompilerServices;
7+
using Xunit;
8+
9+
public class Runtime_115815
10+
{
11+
[Fact]
12+
public static void TestEntryPoint()
13+
{
14+
var destination = new KeyValuePair<Container, double>[1_000_000];
15+
16+
// loop to make this method fully interruptible + to get into OSR version
17+
for (int i = 0; i < destination.Length; i++)
18+
{
19+
destination[i] = default;
20+
}
21+
22+
for (int i = 0; i < 5; i++)
23+
{
24+
for (int j = 0; j < destination.Length; j++)
25+
{
26+
destination[j] = GetValue(j);
27+
}
28+
29+
Thread.Sleep(10);
30+
}
31+
}
32+
33+
[MethodImpl(MethodImplOptions.NoInlining)]
34+
private static KeyValuePair<Container, double> GetValue(int i)
35+
=> KeyValuePair.Create(new Container(i.ToString()), (double)i);
36+
37+
private struct Container
38+
{
39+
public string Name;
40+
public Container(string name) { this.Name = name; }
41+
}
42+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<Optimize>True</Optimize>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<Compile Include="$(MSBuildProjectName).cs" />
7+
</ItemGroup>
8+
</Project>

0 commit comments

Comments
 (0)