Skip to content

Commit

Permalink
JIT: Remove GTF_CALL_M_UNMGD_THISCALL and badcode on thiscall with 0 …
Browse files Browse the repository at this point in the history
…args (#71882)

Fix #71874
  • Loading branch information
jakobbotsch committed Jul 19, 2022
1 parent 56b22b5 commit a1f1e7c
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 22 deletions.
9 changes: 1 addition & 8 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9729,14 +9729,7 @@ void cTreeFlags(Compiler* comp, GenTree* tree)
chars += printf("[CALL_M_SPECIAL_INTRINSIC]");
}

if (call->IsUnmanaged())
{
if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
{
chars += printf("[CALL_M_UNMGD_THISCALL]");
}
}
else if (call->IsVirtualStub())
if (call->IsVirtualStub())
{
if (call->gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT)
{
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9935,10 +9935,6 @@ void Compiler::gtDispNodeName(GenTree* tree)
{
gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " popargs");
}
if (tree->AsCall()->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
{
gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " thiscall");
}
#ifdef TARGET_X86
gtfTypeBufWalk += SimpleSprintf_s(gtfTypeBufWalk, gtfTypeBuf, sizeof(gtfTypeBuf), " %s",
GetCallConvName(tree->AsCall()->GetUnmanagedCallConv()));
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -3980,7 +3980,6 @@ enum GenTreeCallFlags : unsigned int
GTF_CALL_M_NOGCCHECK = 0x00000020, // not a call for computing full interruptability and therefore no GC check is required.
GTF_CALL_M_SPECIAL_INTRINSIC = 0x00000040, // function that could be optimized as an intrinsic
// in special cases. Used to optimize fast way out in morphing
GTF_CALL_M_UNMGD_THISCALL = 0x00000080, // "this" pointer (first argument) should be enregistered (only for GTF_CALL_UNMANAGED)
GTF_CALL_M_VIRTSTUB_REL_INDIRECT = 0x00000080, // the virtstub is indirected through a relative address (only for GTF_CALL_VIRT_STUB)
GTF_CALL_M_NONVIRT_SAME_THIS = 0x00000080, // callee "this" pointer is equal to caller this pointer (only for GTF_CALL_NONVIRT)
GTF_CALL_M_FRAME_VAR_DEATH = 0x00000100, // the compLvFrameListRoot variable dies here (last use)
Expand Down
14 changes: 7 additions & 7 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8501,6 +8501,11 @@ void Compiler::impCheckForPInvokeCall(
call->gtCallMoreFlags |= GTF_CALL_M_SUPPRESS_GC_TRANSITION;
}

if ((unmanagedCallConv == CorInfoCallConvExtension::Thiscall) && (sig->numArgs == 0))
{
BADCODE("thiscall with 0 arguments");
}

// If we can't get the unmanaged calling convention or the calling convention is unsupported in the JIT,
// return here without inlining the native call.
if (unmanagedCallConv == CorInfoCallConvExtension::Managed ||
Expand Down Expand Up @@ -8574,11 +8579,6 @@ void Compiler::impCheckForPInvokeCall(
{
call->gtFlags |= GTF_CALL_POP_ARGS;
}

if (unmanagedCallConv == CorInfoCallConvExtension::Thiscall)
{
call->gtCallMoreFlags |= GTF_CALL_M_UNMGD_THISCALL;
}
}

GenTreeCall* Compiler::impImportIndirectCall(CORINFO_SIG_INFO* sig, const DebugInfo& di)
Expand Down Expand Up @@ -8649,7 +8649,7 @@ void Compiler::impPopArgsForUnmanagedCall(GenTreeCall* call, CORINFO_SIG_INFO* s
// For "thiscall", the first argument goes in a register. Since its
// order does not need to be changed, we do not need to spill it

if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
if (call->unmgdCallConv == CorInfoCallConvExtension::Thiscall)
{
assert(argsToReverse);
argsToReverse--;
Expand Down Expand Up @@ -8694,7 +8694,7 @@ void Compiler::impPopArgsForUnmanagedCall(GenTreeCall* call, CORINFO_SIG_INFO* s

impPopReverseCallArgs(sig, call, sig->numArgs - argsToReverse);

if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
if (call->unmgdCallConv == CorInfoCallConvExtension::Thiscall)
{
GenTree* thisPtr = call->gtArgs.GetArgByIndex(0)->GetNode();
impBashVarAddrsToI(thisPtr);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2078,7 +2078,7 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call
{
noway_assert(intArgRegNum == 0);

if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
if (call->unmgdCallConv == CorInfoCallConvExtension::Thiscall)
{
noway_assert((call->gtArgs.GetArgByIndex(0)->GetEarlyNode() == nullptr) ||
(call->gtArgs.GetArgByIndex(0)->GetEarlyNode()->TypeGet() == TYP_I_IMPL) ||
Expand Down
62 changes: 62 additions & 0 deletions src/tests/JIT/Directed/callconv/ThisCall/EmptyThisCallTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Reflection;
using System.Text;
using Xunit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

unsafe class ThisCallNative
{
[DllImport(nameof(ThisCallNative), CallingConvention = CallingConvention.ThisCall, EntryPoint = "GetWidthAsLongFromManaged")]
public static extern int ThisCallWithEmptySignature();
}

unsafe class EmptyThisCallTest
{
public static int Main(string[] args)
{
try
{
delegate* unmanaged[Thiscall]<void*, int> fn = &Foo;
CalliEmptyThisCall((delegate* unmanaged[Thiscall]<int>)fn);
Console.WriteLine("FAIL: thiscall fptr with no args should have failed");
return -1;
}
catch (InvalidProgramException)
{
Console.WriteLine("thiscall fptr with no args failed as expected");
}

try
{
PinvokeEmptyThisCall();
Console.WriteLine("FAIL: pinvoke thiscall with no args should have failed");
return -1;
}
catch (InvalidProgramException)
{
Console.WriteLine("thiscall pinvoke with no args failed as expected");
}

return 100;
}

[UnmanagedCallersOnly(CallConvs = new [] {typeof(CallConvThiscall)})]
private static int Foo(void* a)
{
return 0;
}

private static int CalliEmptyThisCall(delegate* unmanaged[Thiscall]<int> fn)
{
return fn();
}

private static void PinvokeEmptyThisCall()
{
ThisCallNative.ThisCallWithEmptySignature();
}
}
13 changes: 13 additions & 0 deletions src/tests/JIT/Directed/callconv/ThisCall/EmptyThisCallTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
<ItemGroup>
<CMakeProjectReference Include="../CMakeLists.txt" />
<ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="*.cs" />
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
<ItemGroup>
<CMakeProjectReference Include="../CMakeLists.txt" />
Expand Down
4 changes: 4 additions & 0 deletions src/tests/issues.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1460,6 +1460,7 @@
<ExcludeList Include = "$(XUnitTestBinBase)/JIT/HardwareIntrinsics/X86/X86Base/Pause*/**">
<Issue>https://github.com/dotnet/runtime/issues/61693</Issue>
</ExcludeList>

<ExcludeList Include = "$(XunitTestBinBase)/reflection/GenericAttribute/**">
<Issue>https://github.com/dotnet/runtime/issues/56887</Issue>
</ExcludeList>
Expand Down Expand Up @@ -2216,6 +2217,9 @@
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/JitBlue/Runtime_68568/Runtime_68568/*">
<Issue>Tests coreclr's handling of switches on natively sized integers</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/callconv/ThisCall/EmptyThisCallTest/*">
<Issue>Tests that 'thiscall' with an empty signature results in InvalidProgramException, which is coreclr-only behavior</Issue>
</ExcludeList>
</ItemGroup>

<!-- Known failures for mono runtime on Windows -->
Expand Down

0 comments on commit a1f1e7c

Please sign in to comment.