Skip to content

Commit d575a6f

Browse files
[release/6.0] Add explicit null-check for tailcalls to VSD (#62769)
* Add explicit null-check for tailcalls to VSD There is already a comment that this is necessary, but it is only being done for x86 tailcalls via jit helper. Do it for normal tailcalls to VSD as well. Fix #61486 * Revert cleanup to make potential backport easier Co-authored-by: Jakob Botsch Nielsen <[email protected]>
1 parent a8b733b commit d575a6f

File tree

3 files changed

+63
-9
lines changed

3 files changed

+63
-9
lines changed

src/coreclr/jit/morph.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7896,6 +7896,15 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call)
78967896
// Avoid potential extra work for the return (for example, vzeroupper)
78977897
call->gtType = TYP_VOID;
78987898

7899+
// The runtime requires that we perform a null check on the `this` argument before
7900+
// tail calling to a virtual dispatch stub. This requirement is a consequence of limitations
7901+
// in the runtime's ability to map an AV to a NullReferenceException if
7902+
// the AV occurs in a dispatch stub that has unmanaged caller.
7903+
if (call->IsVirtualStub())
7904+
{
7905+
call->gtFlags |= GTF_CALL_NULLCHECK;
7906+
}
7907+
78997908
// Do some target-specific transformations (before we process the args,
79007909
// etc.) for the JIT helper case.
79017910
if (tailCallViaJitHelper)
@@ -8622,15 +8631,6 @@ void Compiler::fgMorphTailCallViaJitHelper(GenTreeCall* call)
86228631
JITDUMP("fgMorphTailCallViaJitHelper (before):\n");
86238632
DISPTREE(call);
86248633

8625-
// The runtime requires that we perform a null check on the `this` argument before
8626-
// tail calling to a virtual dispatch stub. This requirement is a consequence of limitations
8627-
// in the runtime's ability to map an AV to a NullReferenceException if
8628-
// the AV occurs in a dispatch stub that has unmanaged caller.
8629-
if (call->IsVirtualStub())
8630-
{
8631-
call->gtFlags |= GTF_CALL_NULLCHECK;
8632-
}
8633-
86348634
// For the helper-assisted tail calls, we need to push all the arguments
86358635
// into a single list, and then add a few extra at the beginning or end.
86368636
//
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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;
5+
using System.Reflection;
6+
using System.Runtime.CompilerServices;
7+
8+
public class Runtime_61486
9+
{
10+
public static int Main()
11+
{
12+
var my = new My(new My(null));
13+
var m = my.GetType().GetMethod("M");
14+
try
15+
{
16+
m.Invoke(my, null);
17+
return -1;
18+
}
19+
catch (TargetInvocationException ex) when (ex.InnerException is NullReferenceException)
20+
{
21+
return 100;
22+
}
23+
}
24+
25+
public interface IFace
26+
{
27+
void M();
28+
}
29+
30+
public class My : IFace
31+
{
32+
private IFace _face;
33+
34+
public My(IFace face)
35+
{
36+
_face = face;
37+
}
38+
39+
// We cannot handle a null ref inside a VSD if the caller is not
40+
// managed frame. This test is verifying that JIT null checks ahead of
41+
// time in this case.
42+
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
43+
public void M() => _face.M();
44+
}
45+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<Optimize>True</Optimize>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<Compile Include="$(MSBuildProjectName).cs" />
8+
</ItemGroup>
9+
</Project>

0 commit comments

Comments
 (0)