diff options
author | Fadi Hanna <fadim@microsoft.com> | 2018-06-27 20:26:31 +0300 |
---|---|---|
committer | Fadi Hanna <fadim@microsoft.com> | 2018-06-27 20:26:31 +0300 |
commit | 8a67e171ceab76a4d23131e51bc13c84cb2479d8 (patch) | |
tree | fb9bdc5223bcfa15cea5525fdcca4d381a26686a /src/ILCompiler.Compiler | |
parent | d6905df41a109b97c424a49eabbd8909f3a9d28d (diff) |
Changing the interface method resolution logic used in building the sealed vtable and the interface dispatch map to work with type definitions instead of instantiated types, to correctly handle the cases where we get generic interface collapsing, and when the implementing method ends up in the sealed vtable (This was causing the interface resolution logic at runtime to fail).
This also fixes the cases of dynamic types, since we use fully canonical instantiations as templates, and these canonical instantiations can suffer from the same generic collapsing problem.
[tfs-changeset: 1705787]
Diffstat (limited to 'src/ILCompiler.Compiler')
-rw-r--r-- | src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs | 29 | ||||
-rw-r--r-- | src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/SealedVTableNode.cs | 25 |
2 files changed, 40 insertions, 14 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs index b631efaff..57c4299af 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs @@ -76,9 +76,9 @@ namespace ILCompiler.DependencyAnalysis if (!type.IsArray && !type.IsDefType) return false; - DefType defType = type.GetClosestDefType(); + TypeDesc declType = type.GetClosestDefType().GetTypeDefinition(); - foreach (DefType interfaceType in defType.RuntimeInterfaces) + foreach (DefType interfaceType in declType.RuntimeInterfaces) { IEnumerable<MethodDesc> slots; @@ -96,7 +96,7 @@ namespace ILCompiler.DependencyAnalysis if (declMethod.Signature.IsStatic) continue; - var implMethod = defType.ResolveInterfaceMethodToVirtualMethodOnType(declMethod); + var implMethod = declType.ResolveInterfaceMethodToVirtualMethodOnType(declMethod); if (implMethod != null) return true; } @@ -109,10 +109,15 @@ namespace ILCompiler.DependencyAnalysis { var entryCountReservation = builder.ReserveInt(); int entryCount = 0; - - for (int interfaceIndex = 0; interfaceIndex < _type.RuntimeInterfaces.Length; interfaceIndex++) + + TypeDesc declType = _type.GetClosestDefType(); + + // Catch any runtime interface collapsing. We shouldn't have any + Debug.Assert(declType.RuntimeInterfaces.Length == declType.GetTypeDefinition().RuntimeInterfaces.Length); + + for (int interfaceIndex = 0; interfaceIndex < declType.RuntimeInterfaces.Length; interfaceIndex++) { - var interfaceType = _type.RuntimeInterfaces[interfaceIndex]; + var interfaceType = declType.GetTypeDefinition().RuntimeInterfaces[interfaceIndex]; Debug.Assert(interfaceType.IsInterface); IReadOnlyList<MethodDesc> virtualSlots = factory.VTable(interfaceType).Slots; @@ -120,15 +125,23 @@ namespace ILCompiler.DependencyAnalysis for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++) { MethodDesc declMethod = virtualSlots[interfaceMethodSlot]; - var implMethod = _type.GetClosestDefType().ResolveInterfaceMethodToVirtualMethodOnType(declMethod); + var implMethod = declType.GetTypeDefinition().ResolveInterfaceMethodToVirtualMethodOnType(declMethod); // Interface methods first implemented by a base type in the hierarchy will return null for the implMethod (runtime interface // dispatch will walk the inheritance chain). if (implMethod != null) { + TypeDesc implType = declType; + while (!implType.HasSameTypeDefinition(implMethod.OwningType)) + implType = implType.BaseType; + + MethodDesc targetMethod = implMethod; + if (!implType.IsTypeDefinition) + targetMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(implMethod.GetTypicalMethodDefinition(), (InstantiatedType)implType); + builder.EmitShort(checked((short)interfaceIndex)); builder.EmitShort(checked((short)(interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0)))); - builder.EmitShort(checked((short)VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, implMethod, _type.GetClosestDefType()))); + builder.EmitShort(checked((short)VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, declType))); entryCount++; } } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/SealedVTableNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/SealedVTableNode.cs index ec1dca987..c2a792246 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/SealedVTableNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/SealedVTableNode.cs @@ -98,27 +98,40 @@ namespace ILCompiler.DependencyAnalysis for (int i = 0; i < virtualSlots.Count; i++) { - MethodDesc implMethod = _type.GetClosestDefType().FindVirtualFunctionTargetMethodOnObjectType(virtualSlots[i]); + MethodDesc implMethod = declType.FindVirtualFunctionTargetMethodOnObjectType(virtualSlots[i]); if (implMethod.CanMethodBeInSealedVTable()) _sealedVTableEntries.Add(implMethod); } - for (int interfaceIndex = 0; interfaceIndex < _type.RuntimeInterfaces.Length; interfaceIndex++) + // Catch any runtime interface collapsing. We shouldn't have any + Debug.Assert(declType.RuntimeInterfaces.Length == declType.GetTypeDefinition().RuntimeInterfaces.Length); + + for (int interfaceIndex = 0; interfaceIndex < declType.RuntimeInterfaces.Length; interfaceIndex++) { - var interfaceType = _type.RuntimeInterfaces[interfaceIndex]; + var interfaceType = declType.GetTypeDefinition().RuntimeInterfaces[interfaceIndex]; virtualSlots = factory.VTable(interfaceType).Slots; for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++) { MethodDesc declMethod = virtualSlots[interfaceMethodSlot]; - var implMethod = _type.GetClosestDefType().ResolveInterfaceMethodToVirtualMethodOnType(declMethod); + var implMethod = declType.GetTypeDefinition().ResolveInterfaceMethodToVirtualMethodOnType(declMethod); // Interface methods first implemented by a base type in the hierarchy will return null for the implMethod (runtime interface // dispatch will walk the inheritance chain). - if (implMethod != null && implMethod.CanMethodBeInSealedVTable() && implMethod.OwningType != _type) - _sealedVTableEntries.Add(implMethod); + if (implMethod != null && implMethod.CanMethodBeInSealedVTable() && !implMethod.OwningType.HasSameTypeDefinition(declType)) + { + TypeDesc implType = declType; + while (!implType.HasSameTypeDefinition(implMethod.OwningType)) + implType = implType.BaseType; + + MethodDesc targetMethod = implMethod; + if (!implType.IsTypeDefinition) + targetMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(implMethod.GetTypicalMethodDefinition(), (InstantiatedType)implType); + + _sealedVTableEntries.Add(targetMethod); + } } } |