From 7f4560bdec0c33ff4f5805cb2fe6f2814b0a7e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 19 Jan 2017 13:36:23 -0800 Subject: Fix handling of constrained method calls from shared generic code (#2527) Don't track runtime determined dependencies if we're generating a call to a constrained method. The more complicated case is tracked in #2526. --- src/JitInterface/src/CorInfoImpl.cs | 7 ++++++- tests/src/Simple/Generics/Generics.cs | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/JitInterface/src/CorInfoImpl.cs b/src/JitInterface/src/CorInfoImpl.cs index 2064ed4de..89b8d6a7a 100644 --- a/src/JitInterface/src/CorInfoImpl.cs +++ b/src/JitInterface/src/CorInfoImpl.cs @@ -2659,7 +2659,11 @@ namespace Internal.JitInterface // to abort the inlining attempt if the inlinee does any generic lookups. bool inlining = contextMethod != MethodBeingCompiled; - if (targetMethod.IsSharedByGenericInstantiations && !inlining) + // If we resolved a constrained call, calling GetRuntimeDeterminedObjectForToken below would + // result in getting back the unresolved target. Don't capture runtime determined dependencies + // in that case and rely on the dependency analysis computing them based on seeing a call to the + // canonical method body. + if (targetMethod.IsSharedByGenericInstantiations && !inlining && !resolvedConstraint) { MethodDesc runtimeDeterminedMethod = (MethodDesc)GetRuntimeDeterminedObjectForToken(ref pResolvedToken); pResult.codePointerOrStubLookup.constLookup.addr = (void*)ObjectToHandle( @@ -2667,6 +2671,7 @@ namespace Internal.JitInterface } else { + Debug.Assert(!forceUseRuntimeLookup); pResult.codePointerOrStubLookup.constLookup.addr = (void*)ObjectToHandle( _compilation.NodeFactory.MethodEntrypoint(targetMethod)); } diff --git a/tests/src/Simple/Generics/Generics.cs b/tests/src/Simple/Generics/Generics.cs index e4fc32932..603d5b792 100644 --- a/tests/src/Simple/Generics/Generics.cs +++ b/tests/src/Simple/Generics/Generics.cs @@ -18,6 +18,7 @@ class Program TestDelegateVirtualMethod.Run(); TestDelegateInterfaceMethod.Run(); TestThreadStaticFieldAccess.Run(); + TestConstrainedMethodCalls.Run(); TestNameManglingCollisionRegression.Run(); TestUnusedGVMsDoNotCrashCompiler.Run(); @@ -383,6 +384,42 @@ class Program } } + class TestConstrainedMethodCalls + { + interface IFoo + { + void Frob(); + } + + struct Foo : IFoo + { + public int FrobbedValue; + + public void Frob() + { + FrobbedValue = 12345; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void DoFrob(ref T t) where T : IFoo + { + // Perform a constrained interface call from shared code. + // This should have been resolved to a direct call at compile time. + t.Frob(); + } + + public static void Run() + { + var foo = new Foo(); + DoFrob, object>(ref foo); + + // If the FrobbedValue doesn't change when we frob, we must have done box+interface call. + if (foo.FrobbedValue != 12345) + throw new Exception(); + } + } + // // Regression test for issue https://github.com/dotnet/corert/issues/1964 // -- cgit v1.2.3