From b1719ac5487faed06ce210f3ca785c5aa72933ad Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Wed, 28 Oct 2020 13:02:40 -0700 Subject: [PATCH 01/11] Add constrained dispatch tests to crossgen2smoke --- src/tests/readytorun/crossgen2/Program.cs | 2 ++ .../readytorun/crossgen2/crossgen2smoke.csproj | 13 +------------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/tests/readytorun/crossgen2/Program.cs b/src/tests/readytorun/crossgen2/Program.cs index 348b0e122e242..cb295ef8e5c59 100644 --- a/src/tests/readytorun/crossgen2/Program.cs +++ b/src/tests/readytorun/crossgen2/Program.cs @@ -2221,6 +2221,8 @@ public static int Main(string[] args) RunTest("FunctionPointerFromAnotherModuleTest", FunctionPointerFromAnotherModuleTest()); RunTest("ExplicitlySizedStructTest", ExplicitlySizedStructTest()); RunTest("ExplicitlySizedClassTest", ExplicitlySizedClassTest()); + RunTest("ConstrainedCallTest612", TypeGeneratorTest612.ConstrainedCallsTest()); + RunTest("ConstrainedCallTest1358", TypeGeneratorTest1358.ConstrainedCallsTest()); RunTest("GenericLdtokenTest", GenericLdtokenTest()); RunTest("ArrayLdtokenTests", ArrayLdtokenTests()); RunTest("TestGenericMDArrayBehavior", TestGenericMDArrayBehavior()); diff --git a/src/tests/readytorun/crossgen2/crossgen2smoke.csproj b/src/tests/readytorun/crossgen2/crossgen2smoke.csproj index eb44c22d788f0..c233cd8dcbd04 100644 --- a/src/tests/readytorun/crossgen2/crossgen2smoke.csproj +++ b/src/tests/readytorun/crossgen2/crossgen2smoke.csproj @@ -1,21 +1,10 @@ - exe - BuildAndRun - true - 0 - true true - - - - - - - + From 8e2d6053e367604a0a9c545ace7cec7e30636c66 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Wed, 28 Oct 2020 13:21:31 -0700 Subject: [PATCH 02/11] Test bits --- .../readytorun/crossgen2/Generated1358.il | 103 +++++++++++++++++ .../readytorun/crossgen2/Generated1358.ilproj | 9 ++ .../readytorun/crossgen2/Generated612.il | 105 ++++++++++++++++++ .../readytorun/crossgen2/Generated612.ilproj | 9 ++ ...ssgen2smoke_donotalwaysusecrossgen2.csproj | 3 + .../readytorun/crossgen2/smoketest.targets | 18 +++ 6 files changed, 247 insertions(+) create mode 100644 src/tests/readytorun/crossgen2/Generated1358.il create mode 100644 src/tests/readytorun/crossgen2/Generated1358.ilproj create mode 100644 src/tests/readytorun/crossgen2/Generated612.il create mode 100644 src/tests/readytorun/crossgen2/Generated612.ilproj create mode 100644 src/tests/readytorun/crossgen2/crossgen2smoke_donotalwaysusecrossgen2.csproj create mode 100644 src/tests/readytorun/crossgen2/smoketest.targets diff --git a/src/tests/readytorun/crossgen2/Generated1358.il b/src/tests/readytorun/crossgen2/Generated1358.il new file mode 100644 index 0000000000000..b0a4adbe25fc8 --- /dev/null +++ b/src/tests/readytorun/crossgen2/Generated1358.il @@ -0,0 +1,103 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) .ver 4:0:0:0 } + +//TYPES IN FORWARDER ASSEMBLIES: + +//TEST ASSEMBLY: +.assembly Generated1358 { .hash algorithm 0x00008004 } +.module Generated1358.dll + +.class private BaseClass0 +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} +.class private BaseClass1 + extends BaseClass0 +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { + ldarg.0 + call instance void BaseClass0::.ctor() + ret + } +} +.class private G3_C1830`1 + extends class G2_C774`2 +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { + ldarg.0 + call instance void class G2_C774`2::.ctor() + ret + } +} +.class private G2_C774`2 + extends class G1_C14`2 +{ + .method public hidebysig newslot virtual instance string 'G1_C14.ClassMethod1350'() cil managed noinlining { + .override method instance string class G1_C14`2::ClassMethod1350<[1]>() + ldstr "G2_C774::ClassMethod1350.MI.12159<" + ldtoken !!M0 + call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + call string [mscorlib]System.String::Concat(object,object) + ldstr ">()" + call string [mscorlib]System.String::Concat(object,object) + ret + } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { + ldarg.0 + call instance void class G1_C14`2::.ctor() + ret + } +} +.class private G1_C14`2 + implements class IBase2`2, class IBase1`1 +{ + .method public hidebysig newslot virtual instance string ClassMethod1350() cil managed noinlining { + ldstr "G1_C14::ClassMethod1350.4883<" + ldtoken !!M0 + call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + call string [mscorlib]System.String::Concat(object,object) + ldstr ">()" + call string [mscorlib]System.String::Concat(object,object) + ret + } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} +.class interface private abstract IBase2`2<+T0, -T1> +{ +} +.class interface private abstract IBase1`1<+T0> +{ +} +.class public auto ansi beforefieldinit TypeGeneratorTest1358 { + .method static bool M.G2_C774.T.T)W>(!!W 'inst', string exp) cil managed { + .maxstack 14 + ldarga.s 0 + constrained. !!W + callvirt instance string class G2_C774`2::ClassMethod1350() + ldarg.1 + call bool [mscorlib]System.String::Equals(string, string) + ret + } + .method public hidebysig static bool ConstrainedCallsTest() cil managed + { + .maxstack 10 + .locals init (object V_0) + newobj instance void class G3_C1830`1::.ctor() + stloc.0 + ldloc.0 + ldstr "G2_C774::ClassMethod1350.MI.12159()" + call bool TypeGeneratorTest1358::M.G2_C774.T.T>(!!2,string) + ret + } +} diff --git a/src/tests/readytorun/crossgen2/Generated1358.ilproj b/src/tests/readytorun/crossgen2/Generated1358.ilproj new file mode 100644 index 0000000000000..39046f95979f0 --- /dev/null +++ b/src/tests/readytorun/crossgen2/Generated1358.ilproj @@ -0,0 +1,9 @@ + + + Library + SharedLibrary + + + + + \ No newline at end of file diff --git a/src/tests/readytorun/crossgen2/Generated612.il b/src/tests/readytorun/crossgen2/Generated612.il new file mode 100644 index 0000000000000..ed866dead751f --- /dev/null +++ b/src/tests/readytorun/crossgen2/Generated612.il @@ -0,0 +1,105 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) .ver 4:0:0:0 } + +//TYPES IN FORWARDER ASSEMBLIES: + +//TEST ASSEMBLY: +.assembly Generated612 { .hash algorithm 0x00008004 } +.module Generated612.dll + +.class public BaseClass0 +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} +.class public BaseClass1 + extends BaseClass0 +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { + ldarg.0 + call instance void BaseClass0::.ctor() + ret + } +} +.class public G3_C1084`1 + extends G2_C21 + implements class IBase2`2 +{ + .method public hidebysig newslot virtual instance string 'G2_C21.ClassMethod1356'() cil managed noinlining { + .override method instance string G2_C21::ClassMethod1356<[1]>() + ldstr "G3_C1084::ClassMethod1356.MI.14216<" + ldtoken !!M0 + call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + call string [mscorlib]System.String::Concat(object,object) + ldstr ">()" + call string [mscorlib]System.String::Concat(object,object) + ret + } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { + ldarg.0 + call instance void G2_C21::.ctor() + ret + } +} +.class public G2_C21 + extends class G1_C6`2 + implements class IBase2`2, class IBase1`1 +{ + .method public hidebysig newslot virtual instance string ClassMethod1356() cil managed noinlining { + ldstr "G2_C21::ClassMethod1356.4932<" + ldtoken !!M0 + call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + call string [mscorlib]System.String::Concat(object,object) + ldstr ">()" + call string [mscorlib]System.String::Concat(object,object) + ret + } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { + ldarg.0 + call instance void class G1_C6`2::.ctor() + ret + } +} +.class interface public abstract IBase2`2<+T0, -T1> +{ +} +.class public G1_C6`2 + implements class IBase2`2 +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} +.class interface public abstract IBase1`1<+T0> +{ +} +.class public auto ansi beforefieldinit TypeGeneratorTest612 { + .method static bool M.G3_C1084.T)W>(!!W 'inst', string exp) cil managed { + .maxstack 14 + ldarga.s 0 + constrained. !!W + callvirt instance string class G3_C1084`1::ClassMethod1356() + ldarg.1 + call bool [mscorlib]System.String::Equals(string, string) + ret + } + .method public hidebysig static bool ConstrainedCallsTest() cil managed + { + .maxstack 10 + .locals init (object V_0) + newobj instance void class G3_C1084`1::.ctor() + stloc.0 + ldloc.0 + ldstr "G3_C1084::ClassMethod1356.MI.14216()" + call bool TypeGeneratorTest612::M.G3_C1084.T>(!!1,string) + ret + } +} diff --git a/src/tests/readytorun/crossgen2/Generated612.ilproj b/src/tests/readytorun/crossgen2/Generated612.ilproj new file mode 100644 index 0000000000000..1dd5b4f924f3e --- /dev/null +++ b/src/tests/readytorun/crossgen2/Generated612.ilproj @@ -0,0 +1,9 @@ + + + Library + SharedLibrary + + + + + \ No newline at end of file diff --git a/src/tests/readytorun/crossgen2/crossgen2smoke_donotalwaysusecrossgen2.csproj b/src/tests/readytorun/crossgen2/crossgen2smoke_donotalwaysusecrossgen2.csproj new file mode 100644 index 0000000000000..04b56bcc111dc --- /dev/null +++ b/src/tests/readytorun/crossgen2/crossgen2smoke_donotalwaysusecrossgen2.csproj @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/tests/readytorun/crossgen2/smoketest.targets b/src/tests/readytorun/crossgen2/smoketest.targets new file mode 100644 index 0000000000000..5e40fc0a3d4d0 --- /dev/null +++ b/src/tests/readytorun/crossgen2/smoketest.targets @@ -0,0 +1,18 @@ + + + + exe + BuildAndRun + true + 0 + + + + + + + + + + + \ No newline at end of file From 9101b015400fad46328eaeb701665b8ebfb1f320 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Thu, 29 Oct 2020 16:56:41 -0700 Subject: [PATCH 03/11] Fix bug around method signatures where method is referenced via a derived type but is actually defined on a base type - Make MethodWithToken which is reliably IL token dependent always be generated in the CorInfoImpl class, and pass the appropriate context to the MethodWithToken constructor so that it can find the appropriate OwningType. --- .../ReadyToRun/DelegateCtorSignature.cs | 10 +- .../ReadyToRun/InstanceEntryPointTableNode.cs | 2 +- .../ReadyToRun/MethodFixupSignature.cs | 16 ++- .../ReadyToRun/SignatureBuilder.cs | 21 ++- .../ReadyToRunCodegenNodeFactory.cs | 2 +- .../ReadyToRunSymbolNodeFactory.cs | 2 +- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 88 ++++++++++-- .../readytorun/crossgen2/Generated1358.il | 103 --------------- .../readytorun/crossgen2/Generated1358.ilproj | 9 -- .../readytorun/crossgen2/Generated612.il | 105 --------------- .../readytorun/crossgen2/Generated612.ilproj | 9 -- src/tests/readytorun/crossgen2/Program.cs | 8 +- src/tests/readytorun/crossgen2/helperdll.cs | 26 ++++ src/tests/readytorun/crossgen2/helperildll.il | 125 ++++++++++++++++++ .../readytorun/crossgen2/smoketest.targets | 2 - 15 files changed, 271 insertions(+), 257 deletions(-) delete mode 100644 src/tests/readytorun/crossgen2/Generated1358.il delete mode 100644 src/tests/readytorun/crossgen2/Generated1358.ilproj delete mode 100644 src/tests/readytorun/crossgen2/Generated612.il delete mode 100644 src/tests/readytorun/crossgen2/Generated612.ilproj diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs index 5c2650c52616f..dfd8f10a2ccd7 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs @@ -14,12 +14,12 @@ public class DelegateCtorSignature : Signature private readonly IMethodNode _targetMethod; - private readonly ModuleToken _methodToken; + private readonly MethodWithToken _methodToken; public DelegateCtorSignature( TypeDesc delegateType, IMethodNode targetMethod, - ModuleToken methodToken) + MethodWithToken methodToken) { _delegateType = delegateType; _targetMethod = targetMethod; @@ -40,10 +40,10 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) if (!relocsOnly) { - SignatureContext innerContext = builder.EmitFixup(factory, ReadyToRunFixupKind.DelegateCtor, _methodToken.Module, factory.SignatureContext); + SignatureContext innerContext = builder.EmitFixup(factory, ReadyToRunFixupKind.DelegateCtor, _methodToken.Token.Module, factory.SignatureContext); builder.EmitMethodSignature( - new MethodWithToken(_targetMethod.Method, _methodToken, constrainedType: null, unboxing: false), + _methodToken, enforceDefEncoding: false, enforceOwningType: false, innerContext, @@ -88,7 +88,7 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer if (result != 0) return result; - return _methodToken.CompareTo(otherNode._methodToken); + return _methodToken.Token.CompareTo(otherNode._methodToken.Token); } } } diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs index e337c0ea71200..03ccc73b7343b 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs @@ -61,7 +61,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) ArraySignatureBuilder signatureBuilder = new ArraySignatureBuilder(); signatureBuilder.EmitMethodSignature( - new MethodWithToken(method.Method, moduleToken, constrainedType: null, unboxing: false), + new MethodWithToken(method.Method, moduleToken, constrainedType: null, unboxing: false, context: null), enforceDefEncoding: true, enforceOwningType: _factory.CompilationModuleGroup.EnforceOwningType(moduleToken.Module), factory.SignatureContext, diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs index 58ea379d920b4..5ce1d8360e711 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using Internal.JitInterface; using Internal.Text; @@ -32,6 +35,8 @@ public MethodFixupSignature( // Ensure types in signature are loadable and resolvable, otherwise we'll fail later while emitting the signature CompilerTypeSystemContext compilerContext = (CompilerTypeSystemContext)method.Method.Context; compilerContext.EnsureLoadableMethod(method.Method); + compilerContext.EnsureLoadableType(_method.OwningType); + if (method.ConstrainedType != null) compilerContext.EnsureLoadableType(method.ConstrainedType); } @@ -68,8 +73,11 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) } else if (_method.Token.TokenType == CorTokenType.mdtMemberRef) { - fixupKind = ReadyToRunFixupKind.MethodEntry_RefToken; - optimized = true; + if ((_method.OwningType == _method.Method.OwningType) && !_method.OwningTypeRequiresSignatureVariableResolution) + { + fixupKind = ReadyToRunFixupKind.MethodEntry_RefToken; + optimized = true; + } } } } @@ -80,13 +88,13 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { if (method.Token.TokenType == CorTokenType.mdtMethodSpec) { - method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method, throwIfNotFound: false), method.ConstrainedType, unboxing: _method.Unboxing); + method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method, throwIfNotFound: false), method.ConstrainedType, unboxing: _method.Unboxing, null); } else if (!optimized && (method.Token.TokenType == CorTokenType.mdtMemberRef)) { if (method.Method.OwningType.GetTypeDefinition() is EcmaType) { - method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method, throwIfNotFound: false), method.ConstrainedType, unboxing: _method.Unboxing); + method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method, throwIfNotFound: false), method.ConstrainedType, unboxing: _method.Unboxing, null); } } } diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs index fd80e7e74a582..0b779576054a3 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs @@ -412,7 +412,7 @@ public void EmitMethodSignature( { flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_Constrained; } - if (enforceOwningType) + if (enforceOwningType || method.OwningType != method.Method.OwningType || method.OwningTypeRequiresSignatureVariableResolution) { flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; } @@ -430,7 +430,7 @@ public void EmitMethodSignature( EmitUInt(flags); if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) { - EmitTypeSignature(method.Method.OwningType, context); + EmitTypeSignature(method.OwningType, context); } EmitMethodDefToken(method.Token); } @@ -439,10 +439,11 @@ public void EmitMethodSignature( case CorTokenType.mdtMemberRef: { flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MemberRefToken; + bool emitTargetMethodOwningType = false; // Owner type is needed for type specs to instantiating stubs or generics with signature variables still present - if (!method.Method.OwningType.IsDefType && - ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_InstantiatingStub) != 0 || method.Method.OwningType.ContainsSignatureVariables())) + if (!method.OwningType.IsDefType && + ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_InstantiatingStub) != 0 || method.OwningType.ContainsSignatureVariables())) { flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; } @@ -451,6 +452,7 @@ public void EmitMethodSignature( var memberRefMethod = method.Token.Module.GetMethod(MetadataTokens.EntityHandle((int)method.Token.Token)); if (memberRefMethod.OwningType != method.Method.OwningType) { + emitTargetMethodOwningType = true; flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; } } @@ -458,7 +460,15 @@ public void EmitMethodSignature( EmitUInt(flags); if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) { - EmitTypeSignature(method.Method.OwningType, context); + // The type here should be the type referred to by the memberref (if this is one, not the type where the method was eventually found! + if (emitTargetMethodOwningType) + { + EmitTypeSignature(method.Method.OwningType, context); + } + else + { + EmitTypeSignature(method.OwningType, context); + } } EmitMethodRefToken(method.Token); } @@ -538,6 +548,7 @@ private void EmitMethodSpecificationSignature(MethodWithToken method, EmitUInt(flags); if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) { + // The type here should be the type referred to by the memberref (if this is one, not the type where the method was eventually found! EmitTypeSignature(method.Method.OwningType, context); } EmitTokenRid(methodToken.Token); diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index 9f9ebf9366280..cf1e452041c34 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -396,7 +396,7 @@ public IEnumerable EnumerateCompiledMethods(EcmaModule moduleT EcmaModule module = ((EcmaMethod)method.GetTypicalMethodDefinition()).Module; ModuleToken moduleToken = Resolver.GetModuleTokenForMethod(method, throwIfNotFound: true); - IMethodNode methodNodeDebug = MethodEntrypoint(new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false), false, false); + IMethodNode methodNodeDebug = MethodEntrypoint(new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, context: null), false, false); MethodWithGCInfo methodCodeNodeDebug = methodNodeDebug as MethodWithGCInfo; if (methodCodeNodeDebug == null && methodNodeDebug is DelayLoadMethodImport DelayLoadMethodImport) { diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs index 1178d4372c33a..539d4404ebcaf 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs @@ -124,7 +124,7 @@ private void CreateNodeCaches() _codegenNodeFactory, _codegenNodeFactory.HelperImports, ReadyToRunHelper.DelayLoad_Helper_ObjObj, - new DelegateCtorSignature(ctorKey.Type, targetMethodNode, ctorKey.Method.Token)); + new DelegateCtorSignature(ctorKey.Type, targetMethodNode, ctorKey.Method)); }); _checkTypeLayoutCache = new NodeCache(key => diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 3ca5d127aefb1..ccadfff57cea9 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -40,14 +40,82 @@ public class MethodWithToken public readonly ModuleToken Token; public readonly TypeDesc ConstrainedType; public readonly bool Unboxing; + public readonly bool OwningTypeRequiresSignatureVariableResolution; + public readonly TypeDesc OwningType; - public MethodWithToken(MethodDesc method, ModuleToken token, TypeDesc constrainedType, bool unboxing) + + public MethodWithToken(MethodDesc method, ModuleToken token, TypeDesc constrainedType, bool unboxing, object context) { Debug.Assert(!method.IsUnboxingThunk()); Method = method; Token = token; ConstrainedType = constrainedType; Unboxing = unboxing; + OwningType = GetMethodTokenOwningType(this, context, out OwningTypeRequiresSignatureVariableResolution); + } + + private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, object context, out bool owningTypeRequiresSignatureVariableResolution) + { + ModuleToken moduleToken = methodToken.Token; + owningTypeRequiresSignatureVariableResolution = false; + + if (moduleToken.TokenType == CorTokenType.mdtMethodDef) + { + return methodToken.Method.OwningType; + } + + if (moduleToken.TokenType == CorTokenType.mdtMethodSpec) + { + var methodSpecification = moduleToken.MetadataReader.GetMethodSpecification((MethodSpecificationHandle)moduleToken.Handle); + moduleToken = new ModuleToken(moduleToken.Module, methodSpecification.Method); + + if (moduleToken.TokenType == CorTokenType.mdtMethodDef) + { + return methodToken.Method.OwningType; + } + } + + // At this point moduleToken must point at a MemberRef. + Debug.Assert(moduleToken.TokenType == CorTokenType.mdtMemberRef); + var memberRef = moduleToken.MetadataReader.GetMemberReference((MemberReferenceHandle)moduleToken.Handle); + switch (memberRef.Parent.Kind) + { + case HandleKind.TypeDefinition: + case HandleKind.TypeReference: + return moduleToken.Module.GetType(memberRef.Parent); + + case HandleKind.TypeSpecification: + { + var owningTypeNonSignatureResolved = moduleToken.Module.GetType(memberRef.Parent); + TypeDesc result = owningTypeNonSignatureResolved; + if (context != null) + { + Instantiation typeInstantiation; + Instantiation methodInstantiation = new Instantiation(); + + if (context is MethodDesc methodContext) + { + typeInstantiation = methodContext.OwningType.Instantiation; + methodInstantiation = methodContext.Instantiation; + } + else + { + TypeDesc typeContext = (TypeDesc)context; + typeInstantiation = typeContext.Instantiation; + } + + result = owningTypeNonSignatureResolved.InstantiateSignature(typeInstantiation, methodInstantiation); + if (result != owningTypeNonSignatureResolved) + { + owningTypeRequiresSignatureVariableResolution = true; + } + } + return result; + } + + default: + return methodToken.Method.OwningType; + } } public override bool Equals(object obj) @@ -326,7 +394,9 @@ private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref object helperArg = GetRuntimeDeterminedObjectForToken(ref pResolvedToken); if (helperArg is MethodDesc methodDesc) { - helperArg = new MethodWithToken(methodDesc, HandleToModuleToken(ref pResolvedToken), constrainedType, unboxing: false); + var methodIL = (MethodIL)HandleToObject((IntPtr)pResolvedToken.tokenScope); + MethodDesc sharedMethod = methodIL.OwningMethod.GetSharedRuntimeFormMethodTarget(); + helperArg = new MethodWithToken(methodDesc, HandleToModuleToken(ref pResolvedToken), constrainedType, unboxing: false, context: sharedMethod); } GenericContext methodContext = new GenericContext(entityFromContext(pResolvedToken.tokenContext)); @@ -356,7 +426,7 @@ private void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetM TypeDesc delegateTypeDesc = HandleToObject(delegateType); MethodDesc targetMethodDesc = HandleToObject(pTargetMethod.hMethod); Debug.Assert(!targetMethodDesc.IsUnboxingThunk()); - MethodWithToken targetMethod = new MethodWithToken(targetMethodDesc, HandleToModuleToken(ref pTargetMethod), constrainedType: null, unboxing: false); + MethodWithToken targetMethod = new MethodWithToken(targetMethodDesc, HandleToModuleToken(ref pTargetMethod), constrainedType: null, unboxing: false, context: entityFromContext(pTargetMethod.tokenContext)); pLookup.lookupKind.needsRuntimeLookup = false; pLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.DelegateCtor(delegateTypeDesc, targetMethod)); @@ -1613,7 +1683,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol( _compilation.SymbolNodeFactory.InterfaceDispatchCell( - new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType: null, unboxing: false), + new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType: null, unboxing: false, context: entityFromContext(pResolvedToken.tokenContext)), MethodBeingCompiled)); // If the abi of the method isn't stable, this will cause a usage of the RequiresRuntimeJitSymbol, which will trigger a RequiresRuntimeJitException @@ -1652,7 +1722,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO // READYTORUN: FUTURE: Direct calls if possible pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol( _compilation.NodeFactory.MethodEntrypoint( - new MethodWithToken(nonUnboxingMethod, HandleToModuleToken(ref pResolvedToken, nonUnboxingMethod), constrainedType, unboxing: isUnboxingStub), + new MethodWithToken(nonUnboxingMethod, HandleToModuleToken(ref pResolvedToken, nonUnboxingMethod), constrainedType, unboxing: isUnboxingStub, context: entityFromContext(pResolvedToken.tokenContext)), isInstantiatingStub: useInstantiatingStub, isPrecodeImportRequired: (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0)); @@ -1675,7 +1745,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO bool atypicalCallsite = (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_ATYPICAL_CALLSITE) != 0; pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol( _compilation.NodeFactory.DynamicHelperCell( - new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType: null, unboxing: false), + new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType: null, unboxing: false, context: entityFromContext(pResolvedToken.tokenContext)), useInstantiatingStub)); Debug.Assert(!pResult->sig.hasTypeArg()); @@ -1702,7 +1772,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO { pResult->instParamLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper( ReadyToRunHelperId.MethodDictionary, - new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType, unboxing: false))); + new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType, unboxing: false, context: entityFromContext(pResolvedToken.tokenContext)))); } else { @@ -1941,7 +2011,7 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool symbolNode = _compilation.SymbolNodeFactory.CreateReadyToRunHelper( ReadyToRunHelperId.MethodHandle, - new MethodWithToken(md, HandleToModuleToken(ref pResolvedToken), constrainedType: null, unboxing: unboxingStub)); + new MethodWithToken(md, HandleToModuleToken(ref pResolvedToken), constrainedType: null, unboxing: unboxingStub, context: entityFromContext(pResolvedToken.tokenContext))); } break; @@ -2179,7 +2249,7 @@ private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORIN methodDesc = rawPInvoke.Target; EcmaMethod ecmaMethod = (EcmaMethod)methodDesc; ModuleToken moduleToken = new ModuleToken(ecmaMethod.Module, ecmaMethod.Handle); - MethodWithToken methodWithToken = new MethodWithToken(ecmaMethod, moduleToken, constrainedType: null, unboxing: false); + MethodWithToken methodWithToken = new MethodWithToken(ecmaMethod, moduleToken, constrainedType: null, unboxing: false, context: null); if (ecmaMethod.IsSuppressGCTransition()) { diff --git a/src/tests/readytorun/crossgen2/Generated1358.il b/src/tests/readytorun/crossgen2/Generated1358.il deleted file mode 100644 index b0a4adbe25fc8..0000000000000 --- a/src/tests/readytorun/crossgen2/Generated1358.il +++ /dev/null @@ -1,103 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -.assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) .ver 4:0:0:0 } - -//TYPES IN FORWARDER ASSEMBLIES: - -//TEST ASSEMBLY: -.assembly Generated1358 { .hash algorithm 0x00008004 } -.module Generated1358.dll - -.class private BaseClass0 -{ - .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { - ldarg.0 - call instance void [mscorlib]System.Object::.ctor() - ret - } -} -.class private BaseClass1 - extends BaseClass0 -{ - .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { - ldarg.0 - call instance void BaseClass0::.ctor() - ret - } -} -.class private G3_C1830`1 - extends class G2_C774`2 -{ - .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { - ldarg.0 - call instance void class G2_C774`2::.ctor() - ret - } -} -.class private G2_C774`2 - extends class G1_C14`2 -{ - .method public hidebysig newslot virtual instance string 'G1_C14.ClassMethod1350'() cil managed noinlining { - .override method instance string class G1_C14`2::ClassMethod1350<[1]>() - ldstr "G2_C774::ClassMethod1350.MI.12159<" - ldtoken !!M0 - call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) - call string [mscorlib]System.String::Concat(object,object) - ldstr ">()" - call string [mscorlib]System.String::Concat(object,object) - ret - } - .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { - ldarg.0 - call instance void class G1_C14`2::.ctor() - ret - } -} -.class private G1_C14`2 - implements class IBase2`2, class IBase1`1 -{ - .method public hidebysig newslot virtual instance string ClassMethod1350() cil managed noinlining { - ldstr "G1_C14::ClassMethod1350.4883<" - ldtoken !!M0 - call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) - call string [mscorlib]System.String::Concat(object,object) - ldstr ">()" - call string [mscorlib]System.String::Concat(object,object) - ret - } - .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { - ldarg.0 - call instance void [mscorlib]System.Object::.ctor() - ret - } -} -.class interface private abstract IBase2`2<+T0, -T1> -{ -} -.class interface private abstract IBase1`1<+T0> -{ -} -.class public auto ansi beforefieldinit TypeGeneratorTest1358 { - .method static bool M.G2_C774.T.T)W>(!!W 'inst', string exp) cil managed { - .maxstack 14 - ldarga.s 0 - constrained. !!W - callvirt instance string class G2_C774`2::ClassMethod1350() - ldarg.1 - call bool [mscorlib]System.String::Equals(string, string) - ret - } - .method public hidebysig static bool ConstrainedCallsTest() cil managed - { - .maxstack 10 - .locals init (object V_0) - newobj instance void class G3_C1830`1::.ctor() - stloc.0 - ldloc.0 - ldstr "G2_C774::ClassMethod1350.MI.12159()" - call bool TypeGeneratorTest1358::M.G2_C774.T.T>(!!2,string) - ret - } -} diff --git a/src/tests/readytorun/crossgen2/Generated1358.ilproj b/src/tests/readytorun/crossgen2/Generated1358.ilproj deleted file mode 100644 index 39046f95979f0..0000000000000 --- a/src/tests/readytorun/crossgen2/Generated1358.ilproj +++ /dev/null @@ -1,9 +0,0 @@ - - - Library - SharedLibrary - - - - - \ No newline at end of file diff --git a/src/tests/readytorun/crossgen2/Generated612.il b/src/tests/readytorun/crossgen2/Generated612.il deleted file mode 100644 index ed866dead751f..0000000000000 --- a/src/tests/readytorun/crossgen2/Generated612.il +++ /dev/null @@ -1,105 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -.assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) .ver 4:0:0:0 } - -//TYPES IN FORWARDER ASSEMBLIES: - -//TEST ASSEMBLY: -.assembly Generated612 { .hash algorithm 0x00008004 } -.module Generated612.dll - -.class public BaseClass0 -{ - .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { - ldarg.0 - call instance void [mscorlib]System.Object::.ctor() - ret - } -} -.class public BaseClass1 - extends BaseClass0 -{ - .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { - ldarg.0 - call instance void BaseClass0::.ctor() - ret - } -} -.class public G3_C1084`1 - extends G2_C21 - implements class IBase2`2 -{ - .method public hidebysig newslot virtual instance string 'G2_C21.ClassMethod1356'() cil managed noinlining { - .override method instance string G2_C21::ClassMethod1356<[1]>() - ldstr "G3_C1084::ClassMethod1356.MI.14216<" - ldtoken !!M0 - call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) - call string [mscorlib]System.String::Concat(object,object) - ldstr ">()" - call string [mscorlib]System.String::Concat(object,object) - ret - } - .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { - ldarg.0 - call instance void G2_C21::.ctor() - ret - } -} -.class public G2_C21 - extends class G1_C6`2 - implements class IBase2`2, class IBase1`1 -{ - .method public hidebysig newslot virtual instance string ClassMethod1356() cil managed noinlining { - ldstr "G2_C21::ClassMethod1356.4932<" - ldtoken !!M0 - call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) - call string [mscorlib]System.String::Concat(object,object) - ldstr ">()" - call string [mscorlib]System.String::Concat(object,object) - ret - } - .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { - ldarg.0 - call instance void class G1_C6`2::.ctor() - ret - } -} -.class interface public abstract IBase2`2<+T0, -T1> -{ -} -.class public G1_C6`2 - implements class IBase2`2 -{ - .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { - ldarg.0 - call instance void [mscorlib]System.Object::.ctor() - ret - } -} -.class interface public abstract IBase1`1<+T0> -{ -} -.class public auto ansi beforefieldinit TypeGeneratorTest612 { - .method static bool M.G3_C1084.T)W>(!!W 'inst', string exp) cil managed { - .maxstack 14 - ldarga.s 0 - constrained. !!W - callvirt instance string class G3_C1084`1::ClassMethod1356() - ldarg.1 - call bool [mscorlib]System.String::Equals(string, string) - ret - } - .method public hidebysig static bool ConstrainedCallsTest() cil managed - { - .maxstack 10 - .locals init (object V_0) - newobj instance void class G3_C1084`1::.ctor() - stloc.0 - ldloc.0 - ldstr "G3_C1084::ClassMethod1356.MI.14216()" - call bool TypeGeneratorTest612::M.G3_C1084.T>(!!1,string) - ret - } -} diff --git a/src/tests/readytorun/crossgen2/Generated612.ilproj b/src/tests/readytorun/crossgen2/Generated612.ilproj deleted file mode 100644 index 1dd5b4f924f3e..0000000000000 --- a/src/tests/readytorun/crossgen2/Generated612.ilproj +++ /dev/null @@ -1,9 +0,0 @@ - - - Library - SharedLibrary - - - - - \ No newline at end of file diff --git a/src/tests/readytorun/crossgen2/Program.cs b/src/tests/readytorun/crossgen2/Program.cs index cb295ef8e5c59..b0c011e5b94a8 100644 --- a/src/tests/readytorun/crossgen2/Program.cs +++ b/src/tests/readytorun/crossgen2/Program.cs @@ -2164,6 +2164,11 @@ public static int Main(string[] args) TextFileName = EmitTextFileForTesting(); + RunTest("CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller", HelperILDllTests.CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller()); + RunTest("CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller", HelperILDllTests.CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller()); + RunTest("CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCreateDelegate", HelperILDllTests.CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCreateDelegate()); + RunTest("CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller", HelperILDllTests.CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller()); + RunTest("CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller", HelperILDllTests.CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller()); RunTest("NewString", NewString()); RunTest("WriteLine", WriteLine()); RunTest("IsInstanceOf", IsInstanceOf()); @@ -2221,15 +2226,12 @@ public static int Main(string[] args) RunTest("FunctionPointerFromAnotherModuleTest", FunctionPointerFromAnotherModuleTest()); RunTest("ExplicitlySizedStructTest", ExplicitlySizedStructTest()); RunTest("ExplicitlySizedClassTest", ExplicitlySizedClassTest()); - RunTest("ConstrainedCallTest612", TypeGeneratorTest612.ConstrainedCallsTest()); - RunTest("ConstrainedCallTest1358", TypeGeneratorTest1358.ConstrainedCallsTest()); RunTest("GenericLdtokenTest", GenericLdtokenTest()); RunTest("ArrayLdtokenTests", ArrayLdtokenTests()); RunTest("TestGenericMDArrayBehavior", TestGenericMDArrayBehavior()); RunTest("TestWithStructureNonBlittableFieldDueToGenerics", TestWithStructureNonBlittableFieldDueToGenerics()); RunTest("TestSingleElementStructABI", TestSingleElementStructABI()); RunTest("TestEnumLayoutAlignments", TestEnumLayoutAlignments()); - File.Delete(TextFileName); Console.WriteLine($@"{_passedTests.Count} tests pass:"); diff --git a/src/tests/readytorun/crossgen2/helperdll.cs b/src/tests/readytorun/crossgen2/helperdll.cs index 82a4928fabf32..79427e84764d3 100644 --- a/src/tests/readytorun/crossgen2/helperdll.cs +++ b/src/tests/readytorun/crossgen2/helperdll.cs @@ -69,3 +69,29 @@ public int GenericFunction(T genericValue, V genericMethodValue, string toStr return inputIntValue; } } + +public class BaseTypeNonGenericMethodActuallyOnBase +{ + public string Method() + { + return "BaseTypeNonGenericMethodActuallyOnBase::Method"; + } + + public string GenMethod() + { + return "BaseTypeNonGenericMethodActuallyOnBase::GenMethod"; + } +} + +public class BaseTypeGenericMethodActuallyOnBase +{ + public string Method() + { + return "BaseTypeGenericMethodActuallyOnBase::Method"; + } + + public string GenMethod() + { + return "BaseTypeGenericMethodActuallyOnBase::GenMethod"; + } +} diff --git a/src/tests/readytorun/crossgen2/helperildll.il b/src/tests/readytorun/crossgen2/helperildll.il index 752d16c83c151..ed3b7327a6ea0 100644 --- a/src/tests/readytorun/crossgen2/helperildll.il +++ b/src/tests/readytorun/crossgen2/helperildll.il @@ -155,3 +155,128 @@ ret } } + +.class auto ansi public beforefieldinit BaseTypeNonGenericMethodActuallyOnBase_ModuleLocal extends [mscorlib]System.Object +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig instance string Method() cil managed noinlining + { + ldstr "BaseTypeNonGenericMethodActuallyOnBase::Method" + ret + } +} + +.class auto ansi public beforefieldinit DerivedTypeGenericMethodActuallyOnBase_ModuleLocal`1 extends BaseTypeNonGenericMethodActuallyOnBase_ModuleLocal +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void BaseTypeNonGenericMethodActuallyOnBase_ModuleLocal::.ctor() + ret + } +} + +.class auto ansi public beforefieldinit DerivedTypeGenericMethodActuallyOnBase`1 extends [helperdll]BaseTypeNonGenericMethodActuallyOnBase +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [helperdll]BaseTypeNonGenericMethodActuallyOnBase::.ctor() + ret + } +} + +.class auto ansi public beforefieldinit DerivedTypeNonGenericMethodActuallyOnBase`1 extends class [helperdll]BaseTypeGenericMethodActuallyOnBase +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void class [helperdll]BaseTypeGenericMethodActuallyOnBase::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit HelperILDllTests { + + .method static class [mscorlib]System.Func`1 GetDelegateMethodFromGenericType() cil managed noinlining + { + newobj instance void class DerivedTypeGenericMethodActuallyOnBase_ModuleLocal`1::.ctor() + ldftn instance string class DerivedTypeGenericMethodActuallyOnBase_ModuleLocal`1::Method() + newobj instance void class [mscorlib]System.Func`1::.ctor(object, native int) + ret + } + + .method static string CallMethodFromGenericType() cil managed noinlining + { + newobj instance void class DerivedTypeGenericMethodActuallyOnBase`1::.ctor() + callvirt instance string class DerivedTypeGenericMethodActuallyOnBase`1::Method() + ret + } + + .method static string CallGenMethodFromGenericType() cil managed noinlining + { + newobj instance void class DerivedTypeGenericMethodActuallyOnBase`1::.ctor() + callvirt instance string class DerivedTypeGenericMethodActuallyOnBase`1::GenMethod() + ret + } + + .method public hidebysig static bool CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCreateDelegate() cil managed noinlining + { + .maxstack 10 + .locals init (object V_0) + call class [mscorlib]System.Func`1 HelperILDllTests::GetDelegateMethodFromGenericType() + callvirt instance !0 class [mscorlib]System.Func`1::Invoke() + ldstr "BaseTypeNonGenericMethodActuallyOnBase::Method" + call bool [mscorlib]System.String::op_Equality(string,string) + ret + } + + + .method public hidebysig static bool CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller() cil managed noinlining + { + .maxstack 10 + .locals init (object V_0) + call string HelperILDllTests::CallMethodFromGenericType() + ldstr "BaseTypeNonGenericMethodActuallyOnBase::Method" + call bool [mscorlib]System.String::op_Equality(string,string) + ret + } + + .method public hidebysig static bool CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller() cil managed noinlining + { + .maxstack 10 + .locals init (object V_0) + call string HelperILDllTests::CallGenMethodFromGenericType() + ldstr "BaseTypeNonGenericMethodActuallyOnBase::GenMethod" + call bool [mscorlib]System.String::op_Equality(string,string) + ret + } + + .method public hidebysig static bool CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller() cil managed noinlining + { + .maxstack 10 + .locals init (object V_0) + newobj instance void class DerivedTypeGenericMethodActuallyOnBase`1::.ctor() + callvirt instance string class DerivedTypeGenericMethodActuallyOnBase`1::Method() + ldstr "BaseTypeNonGenericMethodActuallyOnBase::Method" + call bool [mscorlib]System.String::op_Equality(string,string) + ret + } + + .method public hidebysig static bool CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller() cil managed noinlining + { + .maxstack 10 + .locals init (object V_0) + newobj instance void class DerivedTypeGenericMethodActuallyOnBase`1::.ctor() + callvirt instance string class DerivedTypeGenericMethodActuallyOnBase`1::GenMethod() + ldstr "BaseTypeNonGenericMethodActuallyOnBase::GenMethod" + call bool [mscorlib]System.String::op_Equality(string,string) + ret + } +} diff --git a/src/tests/readytorun/crossgen2/smoketest.targets b/src/tests/readytorun/crossgen2/smoketest.targets index 5e40fc0a3d4d0..085ef5d2c261c 100644 --- a/src/tests/readytorun/crossgen2/smoketest.targets +++ b/src/tests/readytorun/crossgen2/smoketest.targets @@ -9,8 +9,6 @@ - - From 4f9a2c6f4a72fc14c3951713d290c259407bab8e Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Thu, 29 Oct 2020 17:20:55 -0700 Subject: [PATCH 04/11] Mark tests associated with issue 43466 as fixed. --- src/tests/issues.targets | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 91cc91afff31c..ee9c392a92aee 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -945,24 +945,6 @@ - - https://github.com/dotnet/runtime/issues/43466 - - - https://github.com/dotnet/runtime/issues/43466 - - - https://github.com/dotnet/runtime/issues/43466 - - - https://github.com/dotnet/runtime/issues/43466 - - - https://github.com/dotnet/runtime/issues/43466 - - - https://github.com/dotnet/runtime/issues/43466 - https://github.com/dotnet/runtime/issues/43467 From 8482e340ae47ab744442511bc74e64f45d802031 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 30 Oct 2020 15:07:52 -0700 Subject: [PATCH 05/11] Fix concern where constrained calls do not properly specify the correct OwningType - The OwningType needs to be associated with the token of the signature, not the final resolved method --- .../ReadyToRun/SignatureBuilder.cs | 2 +- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 101 +++++---- src/tests/issues.targets | 202 ------------------ 3 files changed, 60 insertions(+), 245 deletions(-) diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs index 0b779576054a3..e7bed635c0023 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs @@ -549,7 +549,7 @@ private void EmitMethodSpecificationSignature(MethodWithToken method, if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) { // The type here should be the type referred to by the memberref (if this is one, not the type where the method was eventually found! - EmitTypeSignature(method.Method.OwningType, context); + EmitTypeSignature(method.OwningType, context); } EmitTokenRid(methodToken.Token); if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation) != 0) diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index ccadfff57cea9..599adf3394a5f 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -59,20 +59,17 @@ private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, ob ModuleToken moduleToken = methodToken.Token; owningTypeRequiresSignatureVariableResolution = false; - if (moduleToken.TokenType == CorTokenType.mdtMethodDef) - { - return methodToken.Method.OwningType; - } - + // Strip off method spec details. The owning type is only associated with a MethodDef or a MemberRef if (moduleToken.TokenType == CorTokenType.mdtMethodSpec) { var methodSpecification = moduleToken.MetadataReader.GetMethodSpecification((MethodSpecificationHandle)moduleToken.Handle); moduleToken = new ModuleToken(moduleToken.Module, methodSpecification.Method); + } - if (moduleToken.TokenType == CorTokenType.mdtMethodDef) - { - return methodToken.Method.OwningType; - } + if (moduleToken.TokenType == CorTokenType.mdtMethodDef) + { + var methodDefinition = moduleToken.MetadataReader.GetMethodDefinition((MethodDefinitionHandle)moduleToken.Handle); + return HandleContext(moduleToken.Module, methodDefinition.GetDeclaringType(), methodToken.Method.OwningType, context, ref owningTypeRequiresSignatureVariableResolution); } // At this point moduleToken must point at a MemberRef. @@ -82,40 +79,46 @@ private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, ob { case HandleKind.TypeDefinition: case HandleKind.TypeReference: - return moduleToken.Module.GetType(memberRef.Parent); - case HandleKind.TypeSpecification: { - var owningTypeNonSignatureResolved = moduleToken.Module.GetType(memberRef.Parent); - TypeDesc result = owningTypeNonSignatureResolved; - if (context != null) - { - Instantiation typeInstantiation; - Instantiation methodInstantiation = new Instantiation(); - - if (context is MethodDesc methodContext) - { - typeInstantiation = methodContext.OwningType.Instantiation; - methodInstantiation = methodContext.Instantiation; - } - else - { - TypeDesc typeContext = (TypeDesc)context; - typeInstantiation = typeContext.Instantiation; - } - - result = owningTypeNonSignatureResolved.InstantiateSignature(typeInstantiation, methodInstantiation); - if (result != owningTypeNonSignatureResolved) - { - owningTypeRequiresSignatureVariableResolution = true; - } - } - return result; + return HandleContext(moduleToken.Module, memberRef.Parent, methodToken.Method.OwningType, context, ref owningTypeRequiresSignatureVariableResolution); } default: return methodToken.Method.OwningType; } + + TypeDesc HandleContext(EcmaModule module, EntityHandle handle, TypeDesc methodTargetOwner, object context, ref bool owningTypeRequiresSignatureVariableResolution) + { + if (context == null) + { + return methodTargetOwner; + } + + var owningTypeNonSignatureResolved = module.GetType(handle); + TypeDesc result = owningTypeNonSignatureResolved; + + Instantiation typeInstantiation; + Instantiation methodInstantiation = new Instantiation(); + + if (context is MethodDesc methodContext) + { + typeInstantiation = methodContext.OwningType.Instantiation; + methodInstantiation = methodContext.Instantiation; + } + else + { + TypeDesc typeContext = (TypeDesc)context; + typeInstantiation = typeContext.Instantiation; + } + + result = owningTypeNonSignatureResolved.InstantiateSignature(typeInstantiation, methodInstantiation); + if (result != owningTypeNonSignatureResolved) + { + owningTypeRequiresSignatureVariableResolution = true; + } + return result; + } } public override bool Equals(object obj) @@ -750,7 +753,13 @@ private bool canTailCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUC return false; } - private ModuleToken HandleToModuleToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken, MethodDesc methodDesc) + private MethodWithToken ComputeMethodWithToken(MethodDesc method, ref CORINFO_RESOLVED_TOKEN pResolvedToken, TypeDesc constrainedType, bool unboxing) + { + ModuleToken token = HandleToModuleToken(ref pResolvedToken, method, out object context, ref constrainedType); + return new MethodWithToken(method, token, constrainedType: constrainedType, unboxing: unboxing, context: context); + } + + private ModuleToken HandleToModuleToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken, MethodDesc methodDesc, out object context, ref TypeDesc constrainedType) { if (methodDesc != null && (_compilation.NodeFactory.CompilationModuleGroup.VersionsWithMethodBody(methodDesc) || methodDesc.IsPInvoke)) { @@ -758,12 +767,20 @@ private ModuleToken HandleToModuleToken(ref CORINFO_RESOLVED_TOKEN pResolvedToke methodDesc?.GetTypicalMethodDefinition() is EcmaMethod ecmaMethod) { mdToken token = (mdToken)MetadataTokens.GetToken(ecmaMethod.Handle); + + // This is used for de-virtualization of non-generic virtual methods, and should be treated + // as a the methodDesc parameter defining the exact OwningType, not doing resolution through the token. + context = null; + constrainedType = null; + return new ModuleToken(ecmaMethod.Module, token); } } + context = entityFromContext(pResolvedToken.tokenContext); return HandleToModuleToken(ref pResolvedToken); } + private ModuleToken HandleToModuleToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) { mdToken token = pResolvedToken.token; @@ -1683,7 +1700,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol( _compilation.SymbolNodeFactory.InterfaceDispatchCell( - new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType: null, unboxing: false, context: entityFromContext(pResolvedToken.tokenContext)), + ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: null, unboxing: false), MethodBeingCompiled)); // If the abi of the method isn't stable, this will cause a usage of the RequiresRuntimeJitSymbol, which will trigger a RequiresRuntimeJitException @@ -1722,7 +1739,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO // READYTORUN: FUTURE: Direct calls if possible pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol( _compilation.NodeFactory.MethodEntrypoint( - new MethodWithToken(nonUnboxingMethod, HandleToModuleToken(ref pResolvedToken, nonUnboxingMethod), constrainedType, unboxing: isUnboxingStub, context: entityFromContext(pResolvedToken.tokenContext)), + ComputeMethodWithToken(nonUnboxingMethod, ref pResolvedToken, constrainedType, unboxing: isUnboxingStub), isInstantiatingStub: useInstantiatingStub, isPrecodeImportRequired: (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0)); @@ -1745,7 +1762,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO bool atypicalCallsite = (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_ATYPICAL_CALLSITE) != 0; pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol( _compilation.NodeFactory.DynamicHelperCell( - new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType: null, unboxing: false, context: entityFromContext(pResolvedToken.tokenContext)), + ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: null, unboxing: false), useInstantiatingStub)); Debug.Assert(!pResult->sig.hasTypeArg()); @@ -1772,7 +1789,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO { pResult->instParamLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper( ReadyToRunHelperId.MethodDictionary, - new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType, unboxing: false, context: entityFromContext(pResolvedToken.tokenContext)))); + ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: constrainedType, unboxing: false))); } else { @@ -2011,7 +2028,7 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool symbolNode = _compilation.SymbolNodeFactory.CreateReadyToRunHelper( ReadyToRunHelperId.MethodHandle, - new MethodWithToken(md, HandleToModuleToken(ref pResolvedToken), constrainedType: null, unboxing: unboxingStub, context: entityFromContext(pResolvedToken.tokenContext))); + ComputeMethodWithToken(md, ref pResolvedToken, constrainedType: null, unboxing: unboxingStub)); } break; diff --git a/src/tests/issues.targets b/src/tests/issues.targets index ee9c392a92aee..283602ad6b9c8 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -943,208 +943,6 @@ - - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - From 114597a4289c803791e2f6cb7a45a9200413f234 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 30 Oct 2020 15:57:53 -0700 Subject: [PATCH 06/11] Fix crossgen2 composite build --- .../DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs index 01098a7be573e..62b5f5ce8c18e 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs @@ -68,7 +68,8 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); - sb.Append($@"TypeFixupSignature({_fixupKind.ToString()}): {_fieldDesc.ToString()}"); + sb.Append($@"FieldFixupSignature({_fixupKind.ToString()}): "); + sb.Append(nameMangler.GetMangledFieldName(_fieldDesc)); } public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) From 7cdd676c0d580fdca0dde9fb078b2d4b6b0be863 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 30 Oct 2020 16:25:04 -0700 Subject: [PATCH 07/11] Simplify naming and remove duplicate logic from method signature generation --- .../ReadyToRun/MethodFixupSignature.cs | 2 +- .../ReadyToRun/SignatureBuilder.cs | 84 +------------------ .../JitInterface/CorInfoImpl.ReadyToRun.cs | 55 ++++++------ 3 files changed, 34 insertions(+), 107 deletions(-) diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs index 5ce1d8360e711..eaeddd907ea5a 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs @@ -73,7 +73,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) } else if (_method.Token.TokenType == CorTokenType.mdtMemberRef) { - if ((_method.OwningType == _method.Method.OwningType) && !_method.OwningTypeRequiresSignatureVariableResolution) + if (!_method.OwningTypeNotDerivedFromToken) { fixupKind = ReadyToRunFixupKind.MethodEntry_RefToken; optimized = true; diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs index e7bed635c0023..a91aecaa25e41 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs @@ -412,72 +412,12 @@ public void EmitMethodSignature( { flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_Constrained; } - if (enforceOwningType || method.OwningType != method.Method.OwningType || method.OwningTypeRequiresSignatureVariableResolution) + if (enforceOwningType || method.OwningTypeNotDerivedFromToken) { flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; } - if ((method.Method.HasInstantiation || method.Method.OwningType.HasInstantiation) && !method.Method.IsGenericMethodDefinition) - { - EmitMethodSpecificationSignature(method, flags, enforceDefEncoding, context); - } - else - { - switch (method.Token.TokenType) - { - case CorTokenType.mdtMethodDef: - { - EmitUInt(flags); - if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) - { - EmitTypeSignature(method.OwningType, context); - } - EmitMethodDefToken(method.Token); - } - break; - - case CorTokenType.mdtMemberRef: - { - flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MemberRefToken; - bool emitTargetMethodOwningType = false; - - // Owner type is needed for type specs to instantiating stubs or generics with signature variables still present - if (!method.OwningType.IsDefType && - ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_InstantiatingStub) != 0 || method.OwningType.ContainsSignatureVariables())) - { - flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; - } - else if (method.Method.IsArrayMethod()) - { - var memberRefMethod = method.Token.Module.GetMethod(MetadataTokens.EntityHandle((int)method.Token.Token)); - if (memberRefMethod.OwningType != method.Method.OwningType) - { - emitTargetMethodOwningType = true; - flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; - } - } - - EmitUInt(flags); - if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) - { - // The type here should be the type referred to by the memberref (if this is one, not the type where the method was eventually found! - if (emitTargetMethodOwningType) - { - EmitTypeSignature(method.Method.OwningType, context); - } - else - { - EmitTypeSignature(method.OwningType, context); - } - } - EmitMethodRefToken(method.Token); - } - break; - - default: - throw new NotImplementedException(); - } - } + EmitMethodSpecificationSignature(method, flags, enforceDefEncoding, context); if (method.ConstrainedType != null) { @@ -501,7 +441,7 @@ private void EmitMethodSpecificationSignature(MethodWithToken method, uint flags, bool enforceDefEncoding, SignatureContext context) { ModuleToken methodToken = method.Token; - if (method.Method.HasInstantiation) + if (method.Method.HasInstantiation && !method.Method.IsGenericMethodDefinition) { flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation; if (!method.Token.IsNull) @@ -514,23 +454,7 @@ private void EmitMethodSpecificationSignature(MethodWithToken method, } } - if (methodToken.IsNull && !enforceDefEncoding) - { - methodToken = context.GetModuleTokenForMethod(method.Method, throwIfNotFound: false); - } - if (methodToken.IsNull) - { - flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; - methodToken = context.GetModuleTokenForMethod(method.Method); - } - - if (method.Method.OwningType.HasInstantiation) - { - // resolveToken currently resolves the token in the context of a given scope; - // in such case, we receive a method on instantiated type along with the - // generic definition token. - flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; - } + Debug.Assert(!methodToken.IsNull); switch (methodToken.TokenType) { diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 599adf3394a5f..2a5f69d0e035c 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -40,7 +40,7 @@ public class MethodWithToken public readonly ModuleToken Token; public readonly TypeDesc ConstrainedType; public readonly bool Unboxing; - public readonly bool OwningTypeRequiresSignatureVariableResolution; + public readonly bool OwningTypeNotDerivedFromToken; public readonly TypeDesc OwningType; @@ -51,13 +51,13 @@ public MethodWithToken(MethodDesc method, ModuleToken token, TypeDesc constraine Token = token; ConstrainedType = constrainedType; Unboxing = unboxing; - OwningType = GetMethodTokenOwningType(this, context, out OwningTypeRequiresSignatureVariableResolution); + OwningType = GetMethodTokenOwningType(this, context, out OwningTypeNotDerivedFromToken); } - private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, object context, out bool owningTypeRequiresSignatureVariableResolution) + private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, object context, out bool owningTypeNotDerivedFromToken) { ModuleToken moduleToken = methodToken.Token; - owningTypeRequiresSignatureVariableResolution = false; + owningTypeNotDerivedFromToken = false; // Strip off method spec details. The owning type is only associated with a MethodDef or a MemberRef if (moduleToken.TokenType == CorTokenType.mdtMethodSpec) @@ -69,7 +69,7 @@ private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, ob if (moduleToken.TokenType == CorTokenType.mdtMethodDef) { var methodDefinition = moduleToken.MetadataReader.GetMethodDefinition((MethodDefinitionHandle)moduleToken.Handle); - return HandleContext(moduleToken.Module, methodDefinition.GetDeclaringType(), methodToken.Method.OwningType, context, ref owningTypeRequiresSignatureVariableResolution); + return HandleContext(moduleToken.Module, methodDefinition.GetDeclaringType(), methodToken.Method.OwningType, context, ref owningTypeNotDerivedFromToken); } // At this point moduleToken must point at a MemberRef. @@ -81,43 +81,46 @@ private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, ob case HandleKind.TypeReference: case HandleKind.TypeSpecification: { - return HandleContext(moduleToken.Module, memberRef.Parent, methodToken.Method.OwningType, context, ref owningTypeRequiresSignatureVariableResolution); + return HandleContext(moduleToken.Module, memberRef.Parent, methodToken.Method.OwningType, context, ref owningTypeNotDerivedFromToken); } default: return methodToken.Method.OwningType; } - TypeDesc HandleContext(EcmaModule module, EntityHandle handle, TypeDesc methodTargetOwner, object context, ref bool owningTypeRequiresSignatureVariableResolution) + TypeDesc HandleContext(EcmaModule module, EntityHandle handle, TypeDesc methodTargetOwner, object context, ref bool owningTypeNotDerivedFromToken) { - if (context == null) - { - return methodTargetOwner; - } - - var owningTypeNonSignatureResolved = module.GetType(handle); - TypeDesc result = owningTypeNonSignatureResolved; + var tokenOnlyOwningType = module.GetType(handle); + TypeDesc actualOwningType; - Instantiation typeInstantiation; - Instantiation methodInstantiation = new Instantiation(); - - if (context is MethodDesc methodContext) + if (context == null) { - typeInstantiation = methodContext.OwningType.Instantiation; - methodInstantiation = methodContext.Instantiation; + actualOwningType = methodTargetOwner; } else { - TypeDesc typeContext = (TypeDesc)context; - typeInstantiation = typeContext.Instantiation; + Instantiation typeInstantiation; + Instantiation methodInstantiation = new Instantiation(); + + if (context is MethodDesc methodContext) + { + typeInstantiation = methodContext.OwningType.Instantiation; + methodInstantiation = methodContext.Instantiation; + } + else + { + TypeDesc typeContext = (TypeDesc)context; + typeInstantiation = typeContext.Instantiation; + } + + actualOwningType = tokenOnlyOwningType.InstantiateSignature(typeInstantiation, methodInstantiation); } - result = owningTypeNonSignatureResolved.InstantiateSignature(typeInstantiation, methodInstantiation); - if (result != owningTypeNonSignatureResolved) + if (actualOwningType != tokenOnlyOwningType) { - owningTypeRequiresSignatureVariableResolution = true; + owningTypeNotDerivedFromToken = true; } - return result; + return actualOwningType; } } From 2e9c8cb528da8a1695d35f17299c2fa7920f3d95 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 30 Oct 2020 16:26:39 -0700 Subject: [PATCH 08/11] Run crossgen2 composite compilation with multi-core --- src/tests/build.cmd | 4 ++-- src/tests/build.sh | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tests/build.cmd b/src/tests/build.cmd index ea6d47d076f8a..499e069000d8e 100644 --- a/src/tests/build.cmd +++ b/src/tests/build.cmd @@ -637,7 +637,7 @@ set __CrossgenCmd="%__RepoRootDir%\dotnet.cmd" "%CORE_ROOT%\R2RTest\R2RTest.dll" if defined __CompositeBuildMode ( set __CrossgenCmd=%__CrossgenCmd% --composite ) else ( - set __CrossgenCmd=%__CrossgenCmd% --large-bubble + set __CrossgenCmd=%__CrossgenCmd% --large-bubble --crossgen2-parallelism 1 ) set __CrossgenDir=%__BinDir% @@ -659,7 +659,7 @@ if defined __DoCrossgen ( if /i "%__BuildArch%" == "x86" ( set __CrossgenDir=!__CrossgenDir!\x64 ) - set __CrossgenCmd=%__CrossgenCmd% --verify-type-and-field-layout --crossgen2-parallelism 1 --crossgen2-path "!__CrossgenDir!\crossgen2\crossgen2.dll" + set __CrossgenCmd=%__CrossgenCmd% --verify-type-and-field-layout --crossgen2-path "!__CrossgenDir!\crossgen2\crossgen2.dll" ) echo Running %__CrossgenCmd% diff --git a/src/tests/build.sh b/src/tests/build.sh index 9fa47da68efbc..0194966a55c25 100755 --- a/src/tests/build.sh +++ b/src/tests/build.sh @@ -175,6 +175,8 @@ precompile_coreroot_fx() if [[ "$__CompositeBuildMode" != 0 ]]; then crossgenCmd="$crossgenCmd --composite" + else + crossgenCmd="$crossgenCmd --crossgen2-parallelism 1" fi local crossgenDir="$__BinDir" @@ -185,7 +187,7 @@ precompile_coreroot_fx() if [[ "$__DoCrossgen" != 0 ]]; then crossgenCmd="$crossgenCmd --crossgen --nocrossgen2 --crossgen-path \"$crossgenDir/crossgen\"" else - crossgenCmd="$crossgenCmd --verify-type-and-field-layout --crossgen2-parallelism 1 --crossgen2-path \"$crossgenDir/crossgen2/crossgen2.dll\"" + crossgenCmd="$crossgenCmd --verify-type-and-field-layout --crossgen2-path \"$crossgenDir/crossgen2/crossgen2.dll\"" fi echo "Running $crossgenCmd" From 1f2fdabdfe6e367f9bbcaa796e38a9a3c0f48d42 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 30 Oct 2020 16:30:57 -0700 Subject: [PATCH 09/11] Disable non-crossgen2 variant of crossgen2smoke test on Mono --- src/tests/issues.targets | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 283602ad6b9c8..710c7d5723693 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1550,6 +1550,9 @@ needs triage + + needs triage + needs triage From 164a6586cce700423b7a30291afc65048788a0b7 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Sat, 31 Oct 2020 17:55:13 -0700 Subject: [PATCH 10/11] Improve Comparison functions, and fix bug with unnecessarily specific OwningType computation --- .../ReadyToRun/DelegateCtorSignature.cs | 2 +- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 80 ++++++++++++++++++- 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs index dfd8f10a2ccd7..c9863573cf654 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs @@ -88,7 +88,7 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer if (result != 0) return result; - return _methodToken.Token.CompareTo(otherNode._methodToken.Token); + return _methodToken.CompareTo(otherNode._methodToken, comparer); } } } diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 2a5f69d0e035c..85409a7631da2 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -113,7 +113,57 @@ TypeDesc HandleContext(EcmaModule module, EntityHandle handle, TypeDesc methodTa typeInstantiation = typeContext.Instantiation; } - actualOwningType = tokenOnlyOwningType.InstantiateSignature(typeInstantiation, methodInstantiation); + var instantiatedOwningType = tokenOnlyOwningType.InstantiateSignature(typeInstantiation, methodInstantiation); + var canonicalizedOwningType = instantiatedOwningType.ConvertToCanonForm(CanonicalFormKind.Specific); + if (instantiatedOwningType == canonicalizedOwningType) + { + actualOwningType = instantiatedOwningType; + } + else + { + actualOwningType = ComputeActualOwningType(methodTargetOwner, instantiatedOwningType, canonicalizedOwningType); + + // Implement via a helper function, so that managing the loop escape behavior is easier to read + TypeDesc ComputeActualOwningType(TypeDesc methodTargetOwner, TypeDesc instantiatedOwningType, TypeDesc canonicalizedOwningType) + { + // Pick between Canonical and Exact OwningTypes. + // + // If the canonicalizedOwningType is the OwningType (or parent type) of the associated method + // Then return canonicalizedOwningType + // Else If the Exact Owning type is the OwningType (or parent type) of the associated method + // Then return actualOwningType + // Else If the canonicallized owningType (or canonicalized parent type) of the associated method + // Return the canonicalizedOwningType + // Else + // Fail, unexpected behavior + var currentType = canonicalizedOwningType; + while (currentType != null) + { + if (currentType == methodTargetOwner) + return canonicalizedOwningType; + currentType = currentType.BaseType; + } + + currentType = instantiatedOwningType; + while (currentType != null) + { + if (currentType == methodTargetOwner) + return instantiatedOwningType; + currentType = currentType.BaseType; + } + + currentType = canonicalizedOwningType; + while (currentType != null) + { + if (currentType == methodTargetOwner) + return canonicalizedOwningType; + currentType = currentType.BaseType.ConvertToCanonForm(CanonicalFormKind.Specific); + } + + Debug.Assert(false); + throw new Exception(); + } + } } if (actualOwningType != tokenOnlyOwningType) @@ -137,7 +187,15 @@ public override int GetHashCode() public bool Equals(MethodWithToken methodWithToken) { - return Method == methodWithToken.Method && Token.Equals(methodWithToken.Token) && ConstrainedType == methodWithToken.ConstrainedType && Unboxing == methodWithToken.Unboxing; + bool equals = Method == methodWithToken.Method && Token.Equals(methodWithToken.Token) && ConstrainedType == methodWithToken.ConstrainedType && + Unboxing == methodWithToken.Unboxing; + if (equals) + { + Debug.Assert(OwningTypeNotDerivedFromToken == methodWithToken.OwningTypeNotDerivedFromToken); + Debug.Assert(OwningType == methodWithToken.OwningType); + } + + return equals; } public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) @@ -177,7 +235,23 @@ public int CompareTo(MethodWithToken other, TypeSystemComparer comparer) if (result != 0) return result; - return Unboxing.CompareTo(other.Unboxing); + result = Unboxing.CompareTo(other.Unboxing); + if (result != 0) + return result; + + // The OwningType/OwningTypeNotDerivedFromToken shoud be equivalent if the above conditions are equal. + Debug.Assert(OwningTypeNotDerivedFromToken == other.OwningTypeNotDerivedFromToken); + Debug.Assert(OwningType == other.OwningType); + + if (OwningTypeNotDerivedFromToken != other.OwningTypeNotDerivedFromToken) + { + if (OwningTypeNotDerivedFromToken) + return 1; + else + return -1; + } + + return comparer.Compare(OwningType, other.OwningType); } } From bdab5e57185487d669af88a76b1231210cb1af5e Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Sat, 31 Oct 2020 21:33:43 -0700 Subject: [PATCH 11/11] Fix issues found in testing --- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 85409a7631da2..67a9f9eefa7f8 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -51,10 +51,10 @@ public MethodWithToken(MethodDesc method, ModuleToken token, TypeDesc constraine Token = token; ConstrainedType = constrainedType; Unboxing = unboxing; - OwningType = GetMethodTokenOwningType(this, context, out OwningTypeNotDerivedFromToken); + OwningType = GetMethodTokenOwningType(this, constrainedType, context, out OwningTypeNotDerivedFromToken); } - private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, object context, out bool owningTypeNotDerivedFromToken) + private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, TypeDesc constrainedType, object context, out bool owningTypeNotDerivedFromToken) { ModuleToken moduleToken = methodToken.Token; owningTypeNotDerivedFromToken = false; @@ -69,7 +69,7 @@ private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, ob if (moduleToken.TokenType == CorTokenType.mdtMethodDef) { var methodDefinition = moduleToken.MetadataReader.GetMethodDefinition((MethodDefinitionHandle)moduleToken.Handle); - return HandleContext(moduleToken.Module, methodDefinition.GetDeclaringType(), methodToken.Method.OwningType, context, ref owningTypeNotDerivedFromToken); + return HandleContext(moduleToken.Module, methodDefinition.GetDeclaringType(), methodToken.Method.OwningType, constrainedType, context, ref owningTypeNotDerivedFromToken); } // At this point moduleToken must point at a MemberRef. @@ -81,14 +81,14 @@ private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, ob case HandleKind.TypeReference: case HandleKind.TypeSpecification: { - return HandleContext(moduleToken.Module, memberRef.Parent, methodToken.Method.OwningType, context, ref owningTypeNotDerivedFromToken); + return HandleContext(moduleToken.Module, memberRef.Parent, methodToken.Method.OwningType, constrainedType, context, ref owningTypeNotDerivedFromToken); } default: return methodToken.Method.OwningType; } - TypeDesc HandleContext(EcmaModule module, EntityHandle handle, TypeDesc methodTargetOwner, object context, ref bool owningTypeNotDerivedFromToken) + TypeDesc HandleContext(EcmaModule module, EntityHandle handle, TypeDesc methodTargetOwner, TypeDesc constrainedType, object context, ref bool owningTypeNotDerivedFromToken) { var tokenOnlyOwningType = module.GetType(handle); TypeDesc actualOwningType; @@ -115,7 +115,7 @@ TypeDesc HandleContext(EcmaModule module, EntityHandle handle, TypeDesc methodTa var instantiatedOwningType = tokenOnlyOwningType.InstantiateSignature(typeInstantiation, methodInstantiation); var canonicalizedOwningType = instantiatedOwningType.ConvertToCanonForm(CanonicalFormKind.Specific); - if (instantiatedOwningType == canonicalizedOwningType) + if ((instantiatedOwningType == canonicalizedOwningType) || (constrainedType != null)) { actualOwningType = instantiatedOwningType; } @@ -155,9 +155,10 @@ TypeDesc ComputeActualOwningType(TypeDesc methodTargetOwner, TypeDesc instantiat currentType = canonicalizedOwningType; while (currentType != null) { + currentType = currentType.ConvertToCanonForm(CanonicalFormKind.Specific); if (currentType == methodTargetOwner) return canonicalizedOwningType; - currentType = currentType.BaseType.ConvertToCanonForm(CanonicalFormKind.Specific); + currentType = currentType.BaseType; } Debug.Assert(false);