Report instantiation argument in non-virtual interface calls (#20257)
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
Fri, 5 Oct 2018 10:51:06 +0000 (12:51 +0200)
committerGitHub <noreply@github.com>
Fri, 5 Oct 2018 10:51:06 +0000 (12:51 +0200)
The existing code would incorrectly inhibit codegen from generating instantiation argument in non-virtual calls to default interface methods (i.e. those that can happen with the `base` syntax in C#).

Fixes #16775.

src/vm/jitinterface.cpp
src/vm/jitinterface.h
tests/src/Regressions/coreclr/16775/sharedinterfacemethod.il [new file with mode: 0644]
tests/src/Regressions/coreclr/16775/sharedinterfacemethod.ilproj [new file with mode: 0644]

index 293bab9..5067a36 100644 (file)
@@ -5730,7 +5730,9 @@ void CEEInfo::getCallInfo(
     pResult->classFlags = getClassAttribsInternal(pResolvedToken->hClass);
 
     pResult->methodFlags = getMethodAttribsInternal(pResult->hMethod);
-    getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL, /* isCallSite = */ TRUE);
+
+    SignatureKind signatureKind = flags & CORINFO_CALLINFO_CALLVIRT ? SK_VIRTUAL_CALLSITE : SK_CALLSITE;
+    getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL, signatureKind);
 
     if (flags & CORINFO_CALLINFO_VERIFICATION)
     {
@@ -8510,7 +8512,7 @@ CEEInfo::getMethodSigInternal(
     CORINFO_METHOD_HANDLE ftnHnd, 
     CORINFO_SIG_INFO *    sigRet, 
     CORINFO_CLASS_HANDLE  owner,
-    BOOL isCallSite)
+    SignatureKind signatureKind)
 {
     STANDARD_VM_CONTRACT;
 
@@ -8537,13 +8539,16 @@ CEEInfo::getMethodSigInternal(
     if (ftn->RequiresInstArg())
     {
         //
-        // If we are making an interface call that is a default interface method, we need to lie to the JIT.  
+        // If we are making a virtual call to an instance method on an interface, we need to lie to the JIT.  
         // The reason being that we already made sure target is always directly callable (through instantiation stubs), 
         // JIT should not generate shared generics aware call code and insert the secret argument again at the callsite.
         // Otherwise we would end up with two secret generic dictionary arguments (since the stub also provides one).
         //
-        BOOL isDefaultInterfaceMethodCallSite = isCallSite && ftn->IsDefaultInterfaceMethod();
-        if (!isDefaultInterfaceMethodCallSite)
+        BOOL isCallSiteThatGoesThroughInstantiatingStub =
+            signatureKind == SK_VIRTUAL_CALLSITE &&
+            !ftn->IsStatic() &&
+            ftn->GetMethodTable()->IsInterface();
+        if (!isCallSiteThatGoesThroughInstantiatingStub)
             sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
     }
 
index c609237..a4f6576 100644 (file)
@@ -30,6 +30,13 @@ enum StompWriteBarrierCompletionAction
     SWB_EE_RESTART = 0x2
 };
 
+enum SignatureKind
+{
+    SK_NOT_CALLSITE,
+    SK_CALLSITE,
+    SK_VIRTUAL_CALLSITE,
+};
+
 class Stub;
 class MethodDesc;
 class FieldDesc;
@@ -745,7 +752,7 @@ public:
             CORINFO_METHOD_HANDLE ftnHnd,
             CORINFO_SIG_INFO* sigInfo,
             CORINFO_CLASS_HANDLE owner = NULL,
-            BOOL isCallSite = FALSE
+            SignatureKind signatureKind = SK_NOT_CALLSITE
             );
 
     void getEHinfo(
diff --git a/tests/src/Regressions/coreclr/16775/sharedinterfacemethod.il b/tests/src/Regressions/coreclr/16775/sharedinterfacemethod.il
new file mode 100644 (file)
index 0000000..308ead9
--- /dev/null
@@ -0,0 +1,91 @@
+.assembly extern System.Runtime { }
+
+.assembly sharedinterfacemethod { }
+
+.class interface private abstract auto ansi IFoo`1<T>
+{
+  .method public hidebysig virtual newslot instance class [System.Runtime]System.Type Frob() cil managed
+  {
+    ldtoken !0
+    call class [System.Runtime]System.Type class [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
+    ret
+  }
+}
+
+.class private auto ansi beforefieldinit Fooer
+       extends [System.Runtime]System.Object
+       implements class IFoo`1<class [System.Runtime]System.Object>,
+                  class IFoo`1<valuetype [System.Runtime]System.Int32>
+{
+  .method public hidebysig specialname rtspecialname 
+          instance void .ctor() cil managed
+  {
+    ldarg.0
+    call instance void [System.Runtime]System.Object::.ctor()
+    ret
+  }
+}
+
+.method public hidebysig static int32 Main() cil managed
+{
+  .entrypoint
+
+  // Callvirt to a shared interface method
+
+  newobj instance void Fooer::.ctor()
+  callvirt instance class [System.Runtime]System.Type class IFoo`1<valuetype [System.Runtime]System.Int32>::Frob()
+  ldtoken valuetype [System.Runtime]System.Int32
+  call class [System.Runtime]System.Type class [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
+  ceq
+  brtrue UnsharedCallvirtIsGood
+
+  ldc.i4.1
+  ret
+
+UnsharedCallvirtIsGood:
+
+  // Call to a shared interface
+
+  newobj instance void Fooer::.ctor()
+  call instance class [System.Runtime]System.Type class IFoo`1<valuetype [System.Runtime]System.Int32>::Frob()
+  ldtoken valuetype [System.Runtime]System.Int32
+  call class [System.Runtime]System.Type class [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
+  ceq
+  brtrue UnsharedCallIsGood
+
+  ldc.i4.2
+  ret
+
+UnsharedCallIsGood:
+
+  // Callvirt to an unshared interface method
+
+  newobj instance void Fooer::.ctor()
+  callvirt instance class [System.Runtime]System.Type class IFoo`1<class [System.Runtime]System.Object>::Frob()
+  ldtoken class [System.Runtime]System.Object
+  call class [System.Runtime]System.Type class [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
+  ceq
+  brtrue SharedCallvirtIsGood
+
+  ldc.i4.3
+  ret
+
+SharedCallvirtIsGood:
+
+  // Call to an unshared interface method
+
+  newobj instance void Fooer::.ctor()
+  call instance class [System.Runtime]System.Type class IFoo`1<class [System.Runtime]System.Object>::Frob()
+  ldtoken class [System.Runtime]System.Object
+  call class [System.Runtime]System.Type class [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
+  ceq
+  brtrue SharedCallIsGood
+
+  ldc.i4.4
+  ret
+
+SharedCallIsGood:
+
+  ldc.i4 100
+  ret
+}
diff --git a/tests/src/Regressions/coreclr/16775/sharedinterfacemethod.ilproj b/tests/src/Regressions/coreclr/16775/sharedinterfacemethod.ilproj
new file mode 100644 (file)
index 0000000..7521917
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{85DFC527-4DB1-595E-A7D7-E94EE1F8140D}</ProjectGuid>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+    <OutputType>Exe</OutputType>
+    <CLRTestKind>BuildAndRun</CLRTestKind>
+    <CLRTestPriority>0</CLRTestPriority>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Include="sharedinterfacemethod.il" />
+  </ItemGroup>
+
+
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>