diff options
author | Michal Strehovský <MichalStrehovsky@users.noreply.github.com> | 2017-06-13 22:33:28 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-13 22:33:28 +0300 |
commit | f34e790055e0f44fc635690eec5cab56f57c6641 (patch) | |
tree | 962dc52e4879e46b6e32996a4ccd2a4ebb3cf11d | |
parent | 61b5b72107de609d0ea55375f47f8a7c23902496 (diff) | |
parent | 1f3d243d7b39c53e6bfb3cc81a25227d1b0dfb2e (diff) |
Merge pull request #3869 from MichalStrehovsky/nmirrorMerge
Merge master to nmirror
39 files changed, 337 insertions, 270 deletions
diff --git a/src/Common/src/TypeSystem/Common/MethodDesc.cs b/src/Common/src/TypeSystem/Common/MethodDesc.cs index 44dca5049..fcab153bb 100644 --- a/src/Common/src/TypeSystem/Common/MethodDesc.cs +++ b/src/Common/src/TypeSystem/Common/MethodDesc.cs @@ -19,6 +19,7 @@ namespace Internal.TypeSystem UnmanagedCallingConventionCdecl = 0x0001, UnmanagedCallingConventionStdCall = 0x0002, UnmanagedCallingConventionThisCall = 0x0003, + CallingConventionVarargs = 0x0005, Static = 0x0010, } diff --git a/src/Common/src/TypeSystem/Ecma/EcmaSignatureParser.cs b/src/Common/src/TypeSystem/Ecma/EcmaSignatureParser.cs index 749f1ca22..74d604347 100644 --- a/src/Common/src/TypeSystem/Ecma/EcmaSignatureParser.cs +++ b/src/Common/src/TypeSystem/Ecma/EcmaSignatureParser.cs @@ -169,10 +169,7 @@ namespace Internal.TypeSystem.Ecma Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionCdecl == (int)SignatureCallingConvention.CDecl); Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionStdCall == (int)SignatureCallingConvention.StdCall); Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionThisCall == (int)SignatureCallingConvention.ThisCall); - - // Vararg methods are not supported in .NET Core - if (signatureCallConv == SignatureCallingConvention.VarArgs) - throw new TypeSystemException.BadImageFormatException(); + Debug.Assert((int)MethodSignatureFlags.CallingConventionVarargs == (int)SignatureCallingConvention.VarArgs); flags = (MethodSignatureFlags)signatureCallConv; } diff --git a/src/Common/src/TypeSystem/IL/DelegateInfo.cs b/src/Common/src/TypeSystem/IL/DelegateInfo.cs index fd3227729..bcf1f2afe 100644 --- a/src/Common/src/TypeSystem/IL/DelegateInfo.cs +++ b/src/Common/src/TypeSystem/IL/DelegateInfo.cs @@ -119,12 +119,30 @@ namespace Internal.IL { TypeDesc firstParam = delegateSignature[0]; - bool generateOpenInstanceMethod = true; + bool generateOpenInstanceMethod; - if (firstParam.IsValueType || - (!firstParam.IsDefType && !firstParam.IsSignatureVariable) /* no arrays, pointers, byrefs, etc. */) + switch (firstParam.Category) { - generateOpenInstanceMethod = false; + case TypeFlags.Pointer: + case TypeFlags.FunctionPointer: + generateOpenInstanceMethod = false; + break; + + case TypeFlags.ByRef: + firstParam = ((ByRefType)firstParam).ParameterType; + generateOpenInstanceMethod = firstParam.IsSignatureVariable || firstParam.IsValueType; + break; + + case TypeFlags.Array: + case TypeFlags.SzArray: + case TypeFlags.SignatureTypeVariable: + generateOpenInstanceMethod = true; + break; + + default: + Debug.Assert(firstParam.IsDefType); + generateOpenInstanceMethod = !firstParam.IsValueType; + break; } if (generateOpenInstanceMethod) diff --git a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs index a9770431a..2d69417b1 100644 --- a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs +++ b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs @@ -176,6 +176,11 @@ namespace ILCompiler return intrinsicMethod; } + public bool HasFixedSlotVTable(TypeDesc type) + { + return NodeFactory.VTable(type).HasFixedSlots; + } + void ICompilation.Compile(string outputFile, ObjectDumper dumper) { if (dumper != null) diff --git a/src/ILCompiler.Compiler/src/Compiler/CompilationBuilder.cs b/src/ILCompiler.Compiler/src/Compiler/CompilationBuilder.cs index 838606a9d..6a8df8d8f 100644 --- a/src/ILCompiler.Compiler/src/Compiler/CompilationBuilder.cs +++ b/src/ILCompiler.Compiler/src/Compiler/CompilationBuilder.cs @@ -24,6 +24,7 @@ namespace ILCompiler protected OptimizationMode _optimizationMode = OptimizationMode.None; protected bool _generateDebugInfo = false; protected MetadataManager _metadataManager; + protected VTableSliceProvider _vtableSliceProvider = new LazyVTableSliceProvider(); public CompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup compilationGroup, NameMangler nameMangler) { @@ -63,6 +64,12 @@ namespace ILCompiler return this; } + public CompilationBuilder UseVTableSliceProvider(VTableSliceProvider provider) + { + _vtableSliceProvider = provider; + return this; + } + public CompilationBuilder UseDebugInfo(bool generateDebugInfo) { _generateDebugInfo = generateDebugInfo; diff --git a/src/ILCompiler.Compiler/src/Compiler/DelegateCreationInfo.cs b/src/ILCompiler.Compiler/src/Compiler/DelegateCreationInfo.cs index eb69b1146..005af801a 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DelegateCreationInfo.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DelegateCreationInfo.cs @@ -96,7 +96,7 @@ namespace ILCompiler return factory.GenericLookup.MethodEntry(TargetMethod, TargetMethodIsUnboxingThunk); case TargetKind.InterfaceDispatch: - return factory.GenericLookup.VirtualMethodAddress(TargetMethod); + return factory.GenericLookup.VirtualCall(TargetMethod); case TargetKind.MethodHandle: return factory.GenericLookup.MethodHandle(TargetMethod); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs index 3d1378efe..ad73f0a6f 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs @@ -48,7 +48,7 @@ namespace ILCompiler.DependencyAnalysis if (_type.RuntimeInterfaces.Length > 0) dependencyList.Add(factory.InterfaceDispatchMap(_type), "Canonical interface dispatch map"); - dependencyList.Add(factory.VTable(_type), "VTable"); + dependencyList.Add(factory.VTable(closestDefType), "VTable"); if (_type.IsCanonicalSubtype(CanonicalFormKind.Universal)) dependencyList.Add(factory.NativeLayout.TemplateTypeLayout(_type), "Universal generic types always have template layout"); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs index e7889f2aa..1106bea0b 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs @@ -66,7 +66,7 @@ namespace ILCompiler.DependencyAnalysis } } - dependencyList.Add(factory.VTable(_type), "VTable"); + dependencyList.Add(factory.VTable(closestDefType), "VTable"); if (closestDefType.HasInstantiation) { diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs index 979868dd2..e88e44806 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs @@ -231,10 +231,10 @@ namespace ILCompiler.DependencyAnalysis private void AddVirtualMethodUseDependencies(DependencyList dependencyList, NodeFactory factory) { - if (_type.RuntimeInterfaces.Length > 0 && !factory.VTable(_type).HasFixedSlots) - { - DefType closestDefType = _type.GetClosestDefType(); + DefType closestDefType = _type.GetClosestDefType(); + if (_type.RuntimeInterfaces.Length > 0 && !factory.VTable(closestDefType).HasFixedSlots) + { foreach (var implementedInterface in _type.RuntimeInterfaces) { // If the type implements ICastable, the methods are implicitly necessary diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericLookupResult.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericLookupResult.cs index 05d2bb9e7..6b8765c10 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericLookupResult.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericLookupResult.cs @@ -610,7 +610,7 @@ namespace ILCompiler.DependencyAnalysis if (factory.Target.Abi == TargetAbi.CoreRT) { MethodDesc instantiatedMethod = _method.GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(typeInstantiation, methodInstantiation); - return factory.ReadyToRunHelper(ReadyToRunHelperId.VirtualCall, instantiatedMethod); + return factory.InterfaceDispatchCell(instantiatedMethod); } else { @@ -629,27 +629,12 @@ namespace ILCompiler.DependencyAnalysis public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory) { - if (factory.Target.Abi == TargetAbi.CoreRT) - { - return factory.NativeLayout.NotSupportedDictionarySlot; - } - else - { - return factory.NativeLayout.InterfaceCellDictionarySlot(_method); - } + return factory.NativeLayout.InterfaceCellDictionarySlot(_method); } public override void WriteDictionaryTocData(NodeFactory factory, IGenericLookupResultTocWriter writer) { - if (factory.Target.Abi == TargetAbi.CoreRT) - { - // TODO - throw new NotImplementedException(); - } - else - { - writer.WriteData(LookupResultReferenceType(factory), LookupResultType.InterfaceDispatchCell, _method); - } + writer.WriteData(LookupResultReferenceType(factory), LookupResultType.InterfaceDispatchCell, _method); } protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer) @@ -659,81 +644,6 @@ namespace ILCompiler.DependencyAnalysis } /// <summary> - /// Generic lookup result that points to a virtual function address load stub. - /// </summary> - internal sealed class VirtualResolveGenericLookupResult : GenericLookupResult - { - private MethodDesc _method; - - protected override int ClassCode => -12619218; - - public VirtualResolveGenericLookupResult(MethodDesc method) - { - Debug.Assert(method.IsRuntimeDeterminedExactMethod); - Debug.Assert(method.IsVirtual); - - // Normal virtual methods don't need a generic lookup. - Debug.Assert(method.OwningType.IsInterface || method.HasInstantiation); - - _method = method; - } - - public override ISymbolNode GetTarget(NodeFactory factory, Instantiation typeInstantiation, Instantiation methodInstantiation, GenericDictionaryNode dictionary) - { - if (factory.Target.Abi == TargetAbi.CoreRT) - { - MethodDesc instantiatedMethod = _method.GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(typeInstantiation, methodInstantiation); - return factory.InterfaceDispatchCell(instantiatedMethod); - } - else - { - MethodDesc instantiatedMethod = _method.GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation); - return factory.InterfaceDispatchCell(instantiatedMethod, dictionary.GetMangledName(factory.NameMangler)); - } - } - - public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) - { - sb.Append("VirtualResolve_"); - sb.Append(nameMangler.GetMangledMethodName(_method)); - } - - public override string ToString() => $"VirtualResolve: {_method}"; - - public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory) - { - if (factory.Target.Abi == TargetAbi.CoreRT) - { - // We should be able to get rid of this custom ABI handling - // once https://github.com/dotnet/corert/issues/3248 is fixed. - return factory.NativeLayout.NotSupportedDictionarySlot; - } - else - { - return factory.NativeLayout.InterfaceCellDictionarySlot(_method); - } - } - - public override void WriteDictionaryTocData(NodeFactory factory, IGenericLookupResultTocWriter writer) - { - if (factory.Target.Abi == TargetAbi.CoreRT) - { - // TODO - throw new NotImplementedException(); - } - else - { - writer.WriteData(LookupResultReferenceType(factory), LookupResultType.InterfaceDispatchCell, _method); - } - } - - protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer) - { - return comparer.Compare(_method, ((VirtualResolveGenericLookupResult)other)._method); - } - } - - /// <summary> /// Generic lookup result that points to the non-GC static base of a type. /// </summary> internal sealed class TypeNonGCStaticBaseGenericLookupResult : GenericLookupResult diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ILScanNodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ILScanNodeFactory.cs index a920c6732..67c91ccab 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ILScanNodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ILScanNodeFactory.cs @@ -16,7 +16,7 @@ namespace ILCompiler.DependencyAnalysis public sealed class ILScanNodeFactory : NodeFactory { public ILScanNodeFactory(CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup, MetadataManager metadataManager, NameMangler nameMangler) - : base(context, compilationModuleGroup, metadataManager, nameMangler, new LazyGenericsDisabledPolicy()) + : base(context, compilationModuleGroup, metadataManager, nameMangler, new LazyGenericsDisabledPolicy(), new LazyVTableSliceProvider()) { } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs index 007ee65ed..acb7072b7 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Diagnostics; using Internal.Runtime; @@ -13,8 +12,8 @@ namespace ILCompiler.DependencyAnalysis { public class InterfaceDispatchCellNode : ObjectNode, ISymbolDefinitionNode { - MethodDesc _targetMethod; - string _callSiteIdentifier; + private readonly MethodDesc _targetMethod; + private readonly string _callSiteIdentifier; public InterfaceDispatchCellNode(MethodDesc targetMethod, string callSiteIdentifier) { @@ -49,7 +48,22 @@ namespace ILCompiler.DependencyAnalysis public override ObjectNodeSection Section => ObjectNodeSection.DataSection; public override bool StaticDependenciesAreComputed => true; - + + protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) + { + DependencyList result = new DependencyList(); + + if (!factory.VTable(_targetMethod.OwningType).HasFixedSlots) + { + result.Add(factory.VirtualMethodUse(_targetMethod), "Interface method use"); + } + + // TODO: https://github.com/dotnet/corert/issues/3224 + result.Add(factory.ReflectableMethod(_targetMethod), "Abstract reflectable method"); + + return result; + } + public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { ObjectDataBuilder objData = new ObjectDataBuilder(factory, relocsOnly); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs index 3ec7d5fd2..c8f936604 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs @@ -1583,7 +1583,10 @@ namespace ILCompiler.DependencyAnalysis protected sealed override FixupSignatureKind SignatureKind => FixupSignatureKind.InterfaceCall; public sealed override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory) { - return new DependencyListEntry[1] { new DependencyListEntry(_signature, "TypeSignature") }; + yield return new DependencyListEntry(_signature, "TypeSignature"); + + if (!factory.VTable(_method.OwningType).HasFixedSlots) + yield return new DependencyListEntry(factory.VirtualMethodUse(_method), "Slot number"); } protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory) diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.GenericLookups.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.GenericLookups.cs index 73bb229d8..ba32b6a37 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.GenericLookups.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.GenericLookups.cs @@ -58,11 +58,6 @@ namespace ILCompiler.DependencyAnalysis return new VirtualDispatchGenericLookupResult(method); }); - _virtualResolveHelpers = new NodeCache<MethodDesc, GenericLookupResult>(method => - { - return new VirtualResolveGenericLookupResult(method); - }); - _typeThreadStaticBaseIndexSymbols = new NodeCache<TypeDesc, GenericLookupResult>(type => { return new TypeThreadStaticBaseIndexGenericLookupResult(type); @@ -213,13 +208,6 @@ namespace ILCompiler.DependencyAnalysis return _virtualCallHelpers.GetOrAdd(method); } - private NodeCache<MethodDesc, GenericLookupResult> _virtualResolveHelpers; - - public GenericLookupResult VirtualMethodAddress(MethodDesc method) - { - return _virtualResolveHelpers.GetOrAdd(method); - } - private NodeCache<MethodKey, GenericLookupResult> _methodEntrypoints; public GenericLookupResult MethodEntry(MethodDesc method, bool isUnboxingThunk = false) diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs index 2fce7836c..2a2d0f7c8 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs @@ -23,14 +23,16 @@ namespace ILCompiler.DependencyAnalysis private TargetDetails _target; private CompilerTypeSystemContext _context; private CompilationModuleGroup _compilationModuleGroup; + private VTableSliceProvider _vtableSliceProvider; private bool _markingComplete; public NodeFactory(CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup, - MetadataManager metadataManager, NameMangler nameMangler, LazyGenericsPolicy lazyGenericsPolicy) + MetadataManager metadataManager, NameMangler nameMangler, LazyGenericsPolicy lazyGenericsPolicy, VTableSliceProvider vtableSliceProvider) { _target = context.Target; _context = context; _compilationModuleGroup = compilationModuleGroup; + _vtableSliceProvider = vtableSliceProvider; NameMangler = nameMangler; InteropStubManager = new InteropStubManager(compilationModuleGroup, context, new InteropStateManager(compilationModuleGroup.GeneratedAssembly)); CreateNodeCaches(); @@ -412,7 +414,7 @@ namespace ILCompiler.DependencyAnalysis if (CompilationModuleGroup.ShouldProduceFullVTable(type)) return new EagerlyBuiltVTableSliceNode(type); else - return new LazilyBuiltVTableSliceNode(type); + return _vtableSliceProvider.GetSlice(type); }); _methodGenericDictionaries = new NodeCache<MethodDesc, ISymbolNode>(method => diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs index f5f788ee1..e88762751 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs @@ -47,10 +47,8 @@ namespace ILCompiler.DependencyAnalysis return factory.GenericLookup.TypeThreadStaticBaseIndex((TypeDesc)target); case ReadyToRunHelperId.MethodDictionary: return factory.GenericLookup.MethodDictionary((MethodDesc)target); - case ReadyToRunHelperId.VirtualCall: + case ReadyToRunHelperId.VirtualDispatchCell: return factory.GenericLookup.VirtualCall((MethodDesc)target); - case ReadyToRunHelperId.ResolveVirtualFunction: - return factory.GenericLookup.VirtualMethodAddress((MethodDesc)target); case ReadyToRunHelperId.MethodEntry: return factory.GenericLookup.MethodEntry((MethodDesc)target); case ReadyToRunHelperId.DelegateCtor: @@ -129,25 +127,6 @@ namespace ILCompiler.DependencyAnalysis } } break; - - case ReadyToRunHelperId.ResolveVirtualFunction: - { - MethodDesc instantiatedTarget = ((MethodDesc)_target).GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(typeInstantiation, methodInstantiation); - if (!factory.VTable(instantiatedTarget.OwningType).HasFixedSlots) - { - result.Add( - new DependencyListEntry( - factory.VirtualMethodUse(instantiatedTarget), - "Dictionary dependency")); - } - - // TODO: https://github.com/dotnet/corert/issues/3224 - if (instantiatedTarget.IsAbstract) - { - result.Add(new DependencyListEntry(factory.ReflectableMethod(instantiatedTarget), "Abstract reflectable method")); - } - } - break; } // All generic lookups depend on the thing they point to diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs index 1ab4a73f4..c3bfaf83c 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs @@ -31,6 +31,7 @@ namespace ILCompiler.DependencyAnalysis FieldHandle, MethodDictionary, MethodEntry, + VirtualDispatchCell, DefaultConstructor, } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RyuJitNodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RyuJitNodeFactory.cs index 6e22b73da..243f509a0 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RyuJitNodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RyuJitNodeFactory.cs @@ -12,8 +12,9 @@ namespace ILCompiler.DependencyAnalysis { public sealed class RyuJitNodeFactory : NodeFactory { - public RyuJitNodeFactory(CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup, MetadataManager metadataManager, NameMangler nameMangler) - : base(context, compilationModuleGroup, metadataManager, nameMangler, new LazyGenericsDisabledPolicy()) + public RyuJitNodeFactory(CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup, MetadataManager metadataManager, + NameMangler nameMangler, VTableSliceProvider vtableSliceProvider) + : base(context, compilationModuleGroup, metadataManager, nameMangler, new LazyGenericsDisabledPolicy(), vtableSliceProvider) { } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunGenericHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunGenericHelperNode.cs index c49d5eb8f..fca8037df 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunGenericHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunGenericHelperNode.cs @@ -207,9 +207,8 @@ namespace ILCompiler.DependencyAnalysis case ReadyToRunHelperId.MethodHandle: case ReadyToRunHelperId.FieldHandle: case ReadyToRunHelperId.MethodDictionary: - case ReadyToRunHelperId.VirtualCall: - case ReadyToRunHelperId.ResolveVirtualFunction: case ReadyToRunHelperId.MethodEntry: + case ReadyToRunHelperId.VirtualDispatchCell: case ReadyToRunHelperId.DefaultConstructor: { EmitDictionaryLookup(factory, ref encoder, contextRegister, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs index 82247a54b..8e7fbab71 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs @@ -31,27 +31,22 @@ namespace ILCompiler.DependencyAnalysis { MethodDesc targetMethod = (MethodDesc)Target; - if (targetMethod.OwningType.IsInterface) - { - encoder.EmitLEAQ(Register.R10, factory.InterfaceDispatchCell((MethodDesc)Target)); - AddrMode jmpAddrMode = new AddrMode(Register.R10, null, 0, 0, AddrModeSize.Int64); - encoder.EmitJmpToAddrMode(ref jmpAddrMode); - } - else - { - if (relocsOnly) - break; + Debug.Assert(!targetMethod.OwningType.IsInterface); - AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); - encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr); + AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); + encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr); - int pointerSize = factory.Target.PointerSize; + int pointerSize = factory.Target.PointerSize; - int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod); + int slot = 0; + if (!relocsOnly) + { + slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod); Debug.Assert(slot != -1); - AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(pointerSize) + (slot * pointerSize), 0, AddrModeSize.Int64); - encoder.EmitJmpToAddrMode(ref jmpAddrMode); } + + AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(pointerSize) + (slot * pointerSize), 0, AddrModeSize.Int64); + encoder.EmitJmpToAddrMode(ref jmpAddrMode); } break; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs index 5b099551c..2d1e3861f 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs @@ -71,7 +71,7 @@ namespace ILCompiler } public UtcNodeFactory(CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup, IEnumerable<ModuleDesc> inputModules, string metadataFile, string outputFile, UTCNameMangler nameMangler, bool buildMRT) - : base(context, compilationModuleGroup, PickMetadataManager(context, compilationModuleGroup, inputModules, metadataFile), nameMangler, new AttributeDrivenLazyGenericsPolicy()) + : base(context, compilationModuleGroup, PickMetadataManager(context, compilationModuleGroup, inputModules, metadataFile), nameMangler, new AttributeDrivenLazyGenericsPolicy(), null) { CreateHostedNodeCaches(); CompilationUnitPrefix = nameMangler.CompilationUnitPrefix; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs index f01fbf406..59777bae9 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs @@ -21,6 +21,7 @@ namespace ILCompiler.DependencyAnalysis public VTableSliceNode(TypeDesc type) { + Debug.Assert(!type.IsArray, "Wanted to call GetClosestDefType?"); _type = type; } @@ -29,6 +30,8 @@ namespace ILCompiler.DependencyAnalysis get; } + public TypeDesc Type => _type; + /// <summary> /// Gets a value indicating whether the slots are assigned at the beginning of the compilation. /// </summary> @@ -41,6 +44,16 @@ namespace ILCompiler.DependencyAnalysis public override bool StaticDependenciesAreComputed => true; + public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory) + { + if (_type.HasBaseType) + { + return new[] { new DependencyListEntry(factory.VTable(_type.BaseType), "Base type VTable") }; + } + + return null; + } + public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null; public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null; @@ -48,9 +61,9 @@ namespace ILCompiler.DependencyAnalysis public override bool HasDynamicDependencies => false; public override bool HasConditionalStaticDependencies => false; - protected IEnumerable<MethodDesc> GetAllVirtualMethods() + protected static IEnumerable<MethodDesc> GetAllVirtualMethods(TypeDesc type) { - foreach (MethodDesc method in _type.GetAllMethods()) + foreach (MethodDesc method in type.GetAllMethods()) { if (method.IsVirtual) yield return method; @@ -59,23 +72,55 @@ namespace ILCompiler.DependencyAnalysis } /// <summary> + /// Represents a VTable slice with fixed slots whose assignment was determined at the time the slice was allocated. + /// </summary> + internal class PrecomputedVTableSliceNode : VTableSliceNode + { + private readonly IReadOnlyList<MethodDesc> _slots; + + public PrecomputedVTableSliceNode(TypeDesc type, IReadOnlyList<MethodDesc> slots) + : base(type) + { + _slots = slots; + } + + public override IReadOnlyList<MethodDesc> Slots + { + get + { + return _slots; + } + } + + public override bool HasFixedSlots + { + get + { + return true; + } + } + } + + /// <summary> /// Represents a VTable slice for a complete type - a type with all virtual method slots generated, /// irrespective of whether they are used. /// </summary> - internal sealed class EagerlyBuiltVTableSliceNode : VTableSliceNode + internal sealed class EagerlyBuiltVTableSliceNode : PrecomputedVTableSliceNode { - private MethodDesc[] _slots; - public EagerlyBuiltVTableSliceNode(TypeDesc type) - : base(type) + : base(type, ComputeSlots(type)) + { + } + + private static IReadOnlyList<MethodDesc> ComputeSlots(TypeDesc type) { var slots = new ArrayBuilder<MethodDesc>(); bool isObjectType = type.IsObject; - DefType defType = _type.GetClosestDefType(); + DefType defType = type.GetClosestDefType(); - IEnumerable<MethodDesc> allSlots = _type.IsInterface ? - GetAllVirtualMethods() : defType.EnumAllVirtualSlots(); + IEnumerable<MethodDesc> allSlots = type.IsInterface ? + GetAllVirtualMethods(type) : defType.EnumAllVirtualSlots(); foreach (var method in allSlots) { @@ -94,36 +139,7 @@ namespace ILCompiler.DependencyAnalysis slots.Add(method); } - _slots = slots.ToArray(); - } - - public override IReadOnlyList<MethodDesc> Slots - { - get - { - return _slots; - } - } - - public override bool HasFixedSlots - { - get - { - return true; - } - } - - public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory) - { - if (_type.HasBaseType) - { - return new DependencyListEntry[] - { - new DependencyListEntry(factory.VTable(_type.BaseType), "Base type VTable") - }; - } - - return null; + return slots.ToArray(); } } @@ -187,16 +203,6 @@ namespace ILCompiler.DependencyAnalysis _usedMethods.Add(virtualMethod); } - public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory) - { - if (_type.HasBaseType) - { - return new[] { new DependencyListEntry(factory.VTable(_type.BaseType), "Base type VTable") }; - } - - return null; - } - public override bool HasConditionalStaticDependencies { get @@ -212,7 +218,7 @@ namespace ILCompiler.DependencyAnalysis DefType defType = _type.GetClosestDefType(); IEnumerable<MethodDesc> allSlots = _type.IsInterface ? - GetAllVirtualMethods() : defType.EnumAllVirtualSlots(); + GetAllVirtualMethods(_type) : defType.EnumAllVirtualSlots(); foreach (var method in allSlots) { diff --git a/src/ILCompiler.Compiler/src/Compiler/ILScanner.cs b/src/ILCompiler.Compiler/src/Compiler/ILScanner.cs index d93aba60c..67c0a8532 100644 --- a/src/ILCompiler.Compiler/src/Compiler/ILScanner.cs +++ b/src/ILCompiler.Compiler/src/Compiler/ILScanner.cs @@ -74,8 +74,9 @@ namespace ILCompiler } } - public ILScanResults Scan() + ILScanResults IILScanner.Scan() { + _nodeFactory.NameMangler.CompilationUnitPrefix = ""; return new ILScanResults(_dependencyGraph.MarkedNodeList); } } @@ -94,17 +95,31 @@ namespace ILCompiler _markedNodes = markedNodes; } - public IEnumerable<MethodDesc> CompiledMethods + public VTableSliceProvider GetVTableLayoutInfo() { - get + return new ScannedVTableProvider(_markedNodes); + } + + private class ScannedVTableProvider : VTableSliceProvider + { + private Dictionary<TypeDesc, IReadOnlyList<MethodDesc>> _vtableSlices = new Dictionary<TypeDesc, IReadOnlyList<MethodDesc>>(); + + public ScannedVTableProvider(ImmutableArray<DependencyNodeCore<NodeFactory>> markedNodes) { - foreach (var node in _markedNodes) + foreach (var node in markedNodes) { - var methodNode = node as ScannedMethodNode; - if (methodNode != null) - yield return methodNode.Method; + var vtableSliceNode = node as VTableSliceNode; + if (vtableSliceNode != null) + { + _vtableSlices.Add(vtableSliceNode.Type, vtableSliceNode.Slots); + } } } + + internal override VTableSliceNode GetSlice(TypeDesc type) + { + return new PrecomputedVTableSliceNode(type, _vtableSlices[type]); + } } } } diff --git a/src/ILCompiler.Compiler/src/Compiler/LibraryRootProvider.cs b/src/ILCompiler.Compiler/src/Compiler/LibraryRootProvider.cs index c4a3805cb..80f6b0171 100644 --- a/src/ILCompiler.Compiler/src/Compiler/LibraryRootProvider.cs +++ b/src/ILCompiler.Compiler/src/Compiler/LibraryRootProvider.cs @@ -84,6 +84,10 @@ namespace ILCompiler { MethodSignature signature = method.Signature; + // Vararg methods are not supported in .NET Core + if ((signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask) == MethodSignatureFlags.CallingConventionVarargs) + throw new TypeSystemException.BadImageFormatException(); + CheckTypeCanBeUsedInSignature(signature.ReturnType); for (int i = 0; i < signature.Length; i++) diff --git a/src/ILCompiler.Compiler/src/Compiler/RyuJitCompilationBuilder.cs b/src/ILCompiler.Compiler/src/Compiler/RyuJitCompilationBuilder.cs index 3de4197dc..27240e366 100644 --- a/src/ILCompiler.Compiler/src/Compiler/RyuJitCompilationBuilder.cs +++ b/src/ILCompiler.Compiler/src/Compiler/RyuJitCompilationBuilder.cs @@ -85,7 +85,7 @@ namespace ILCompiler jitFlagBuilder.Add(CorJitFlag.CORJIT_FLAG_FEATURE_SIMD); } - var factory = new RyuJitNodeFactory(_context, _compilationGroup, _metadataManager, _nameMangler); + var factory = new RyuJitNodeFactory(_context, _compilationGroup, _metadataManager, _nameMangler, _vtableSliceProvider); var jitConfig = new JitConfigProvider(jitFlagBuilder.ToArray(), _ryujitOptions); DependencyAnalyzerBase<NodeFactory> graph = CreateDependencyGraph(factory); diff --git a/src/ILCompiler.Compiler/src/Compiler/VTableSliceProvider.cs b/src/ILCompiler.Compiler/src/Compiler/VTableSliceProvider.cs new file mode 100644 index 000000000..18455f2b4 --- /dev/null +++ b/src/ILCompiler.Compiler/src/Compiler/VTableSliceProvider.cs @@ -0,0 +1,28 @@ +// 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. + +using Internal.TypeSystem; +using ILCompiler.DependencyAnalysis; + +namespace ILCompiler +{ + /// <summary> + /// Provides VTable information for a specific type. + /// </summary> + public abstract class VTableSliceProvider + { + internal abstract VTableSliceNode GetSlice(TypeDesc type); + } + + /// <summary> + /// Provides VTable information that collects data during the compilation to build a VTable for a type. + /// </summary> + public sealed class LazyVTableSliceProvider : VTableSliceProvider + { + internal override VTableSliceNode GetSlice(TypeDesc type) + { + return new LazilyBuiltVTableSliceNode(type); + } + } +} diff --git a/src/ILCompiler.Compiler/src/IL/ILImporter.Scanner.cs b/src/ILCompiler.Compiler/src/IL/ILImporter.Scanner.cs index eeaebf363..a44116f4f 100644 --- a/src/ILCompiler.Compiler/src/IL/ILImporter.Scanner.cs +++ b/src/ILCompiler.Compiler/src/IL/ILImporter.Scanner.cs @@ -592,32 +592,26 @@ namespace Internal.IL _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.GVMLookupForSlot), reason); } - else + else if (method.OwningType.IsInterface) { - ReadyToRunHelperId helper; - if (opcode == ILOpcode.ldvirtftn) + if (exactContextNeedsRuntimeLookup) { - helper = ReadyToRunHelperId.ResolveVirtualFunction; + _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.VirtualDispatchCell, runtimeDeterminedMethod), reason); } else { - Debug.Assert(opcode == ILOpcode.callvirt); - helper = ReadyToRunHelperId.VirtualCall; + _dependencies.Add(_factory.InterfaceDispatchCell(method), reason); } - - if (exactContextNeedsRuntimeLookup && targetMethod.OwningType.IsInterface) - { - _dependencies.Add(GetGenericLookupHelper(helper, runtimeDeterminedMethod), reason); - } - else - { - // Get the slot defining method to make sure our virtual method use tracking gets this right. - // For normal C# code the targetMethod will always be newslot. - MethodDesc slotDefiningMethod = targetMethod.IsNewSlot ? + } + else if (_compilation.HasFixedSlotVTable(method.OwningType)) + { + // No dependencies: virtual call through the vtable + } + else + { + MethodDesc slotDefiningMethod = targetMethod.IsNewSlot ? targetMethod : MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(targetMethod); - - _dependencies.Add(_factory.ReadyToRunHelper(helper, slotDefiningMethod), reason); - } + _dependencies.Add(_factory.VirtualMethodUse(slotDefiningMethod), reason); } } diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj index 25de949da..068828832 100644 --- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj +++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj @@ -309,6 +309,7 @@ <Compile Include="Compiler\SimdHelper.cs" /> <Compile Include="Compiler\VectorOfTFieldLayoutAlgorithm.cs" /> <Compile Include="Compiler\VirtualMethodCallHelper.cs" /> + <Compile Include="Compiler\VTableSliceProvider.cs" /> <Compile Include="Compiler\WindowsNodeMangler.cs" /> <Compile Include="IL\ILImporter.Scanner.cs" /> <Compile Include="IL\Stubs\PInvokeILProvider.cs" /> diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilationBuilder.cs b/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilationBuilder.cs index 7ea68e212..3f56e757c 100644 --- a/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilationBuilder.cs +++ b/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilationBuilder.cs @@ -29,7 +29,7 @@ namespace ILCompiler public override ICompilation ToCompilation() { - CppCodegenNodeFactory factory = new CppCodegenNodeFactory(_context, _compilationGroup, _metadataManager, _nameMangler); + CppCodegenNodeFactory factory = new CppCodegenNodeFactory(_context, _compilationGroup, _metadataManager, _nameMangler, _vtableSliceProvider); DependencyAnalyzerBase<NodeFactory> graph = CreateDependencyGraph(factory); return new CppCodegenCompilation(graph, factory, _compilationRoots, _logger, _config); diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs index 3eaf2ae2a..2a0e66acb 100644 --- a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs +++ b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs @@ -10,8 +10,9 @@ namespace ILCompiler.DependencyAnalysis { public sealed class CppCodegenNodeFactory : NodeFactory { - public CppCodegenNodeFactory(CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup, MetadataManager metadataManager, NameMangler nameMangler) - : base(context, compilationModuleGroup, metadataManager, nameMangler, new LazyGenericsDisabledPolicy()) + public CppCodegenNodeFactory(CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup, MetadataManager metadataManager, + NameMangler nameMangler, VTableSliceProvider vtableSliceProvider) + : base(context, compilationModuleGroup, metadataManager, nameMangler, new LazyGenericsDisabledPolicy(), vtableSliceProvider) { } diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs index 53e9e892d..5e5069a63 100644 --- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs +++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs @@ -1109,7 +1109,7 @@ namespace ILCompiler.CppCodeGen { OutputTypeFields(typeDefinitions, nodeType); - IReadOnlyList<MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(nodeType).Slots; + IReadOnlyList<MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(nodeType.GetClosestDefType()).Slots; int baseSlots = 0; var baseType = nodeType.BaseType; diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs index cac63cb1e..dce48157a 100644 --- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs +++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs @@ -990,7 +990,6 @@ namespace Internal.IL if (callViaInterfaceDispatch) { - _dependencies.Add(_nodeFactory.ReadyToRunHelper(ReadyToRunHelperId.VirtualCall, method)); ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (methodSignature.Length + 1)]; string typeDefName = _writer.GetCppMethodName(method); diff --git a/src/JitInterface/src/CorInfoImpl.cs b/src/JitInterface/src/CorInfoImpl.cs index 9e8c802bf..9c8534db5 100644 --- a/src/JitInterface/src/CorInfoImpl.cs +++ b/src/JitInterface/src/CorInfoImpl.cs @@ -534,6 +534,11 @@ namespace Internal.JitInterface private void Get_CORINFO_SIG_INFO(MethodSignature signature, out CORINFO_SIG_INFO sig) { sig.callConv = (CorInfoCallConv)(signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask); + + // Varargs are not supported in .NET Core + if (sig.callConv == CorInfoCallConv.CORINFO_CALLCONV_VARARG) + throw new TypeSystemException.BadImageFormatException(); + if (!signature.IsStatic) sig.callConv |= CorInfoCallConv.CORINFO_CALLCONV_HASTHIS; TypeDesc returnType = signature.ReturnType; @@ -792,10 +797,66 @@ namespace Internal.JitInterface private CORINFO_MODULE_STRUCT_* getMethodModule(CORINFO_METHOD_STRUCT_* method) { throw new NotImplementedException("getMethodModule"); } + private void getMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection) - { throw new NotImplementedException("getMethodVTableOffset"); } - private CORINFO_METHOD_STRUCT_* resolveVirtualMethod(CORINFO_METHOD_STRUCT_* virtualMethod, CORINFO_CLASS_STRUCT_* implementingClass, CORINFO_CONTEXT_STRUCT* ownerType) - { throw new NotImplementedException("resolveVirtualMethod"); } + { + MethodDesc methodDesc = HandleToObject(method); + int pointerSize = _compilation.TypeSystemContext.Target.PointerSize; + offsetOfIndirection = (uint)CORINFO_VIRTUALCALL_NO_CHUNK.Value; + + // Normalize to the slot defining method. We don't have slot information for the overrides. + methodDesc = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(methodDesc); + + int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(_compilation.NodeFactory, methodDesc); + Debug.Assert(slot != -1); + + offsetAfterIndirection = (uint)(EETypeNode.GetVTableOffset(pointerSize) + slot * pointerSize); + } + + private CORINFO_METHOD_STRUCT_* resolveVirtualMethod(CORINFO_METHOD_STRUCT_* baseMethod, CORINFO_CLASS_STRUCT_* derivedClass, CORINFO_CONTEXT_STRUCT* ownerType) + { + TypeDesc implType = HandleToObject(derivedClass); + + // __Canon cannot be devirtualized + if (implType.IsCanonicalDefinitionType(CanonicalFormKind.Any)) + { + return null; + } + + implType = implType.GetClosestDefType(); + + MethodDesc decl = HandleToObject(baseMethod); + Debug.Assert(decl.IsVirtual); + Debug.Assert(!decl.HasInstantiation); + + MethodDesc impl; + + TypeDesc declOwningType = decl.OwningType; + if (declOwningType.IsInterface) + { + // Interface call devirtualization. + + if (implType.IsValueType) + { + // TODO: this ends up asserting RyuJIT - why? + return null; + } + + if (implType.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + // TODO: attempt to devirtualize methods on canonical interfaces + return null; + } + + impl = implType.ResolveInterfaceMethodTarget(decl); + } + else + { + impl = implType.GetClosestDefType().FindVirtualFunctionTargetMethodOnObjectType(decl); + } + + return impl != null ? ObjectToHandle(impl) : null; + } private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_GENERICHANDLE_RESULT pResult) { @@ -3014,6 +3075,39 @@ namespace Internal.JitInterface // move that assert to some place later though. targetIsFatFunctionPointer = true; } + else if ((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) == 0 + && targetMethod.OwningType.IsInterface) + { + pResult.kind = CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_STUB; + + if (pResult.exactContextNeedsRuntimeLookup) + { + pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup = true; + pResult.codePointerOrStubLookup.runtimeLookup.indirections = CORINFO.USEHELPER; + + // Do not bother computing the runtime lookup if we are inlining. The JIT is going + // to abort the inlining attempt anyway. + MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext); + if (contextMethod == MethodBeingCompiled) + { + pResult.codePointerOrStubLookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod); + pResult.codePointerOrStubLookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.VirtualDispatchCell; + pResult.codePointerOrStubLookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken)); + } + } + else + { + pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup = false; + pResult.codePointerOrStubLookup.constLookup.accessType = InfoAccessType.IAT_PVALUE; + pResult.codePointerOrStubLookup.constLookup.addr = (void*)ObjectToHandle(_compilation.NodeFactory.InterfaceDispatchCell(targetMethod)); + } + } + else if ((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) == 0 + && _compilation.HasFixedSlotVTable(targetMethod.OwningType)) + { + pResult.kind = CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_VTABLE; + pResult.nullInstanceCheck = true; + } else { ReadyToRunHelperId helperId; @@ -3036,18 +3130,12 @@ namespace Internal.JitInterface // Foo<string>.GetHashCode is needed too. if (pResult.exactContextNeedsRuntimeLookup && targetMethod.OwningType.IsInterface) { - pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup = true; - pResult.codePointerOrStubLookup.runtimeLookup.indirections = CORINFO.USEHELPER; - - // Do not bother computing the runtime lookup if we are inlining. The JIT is going - // to abort the inlining attempt anyway. - MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext); - if (contextMethod == MethodBeingCompiled) - { - pResult.codePointerOrStubLookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod); - pResult.codePointerOrStubLookup.lookupKind.runtimeLookupFlags = (ushort)helperId; - pResult.codePointerOrStubLookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken)); - } + // We need JitInterface changes to fully support this. + // If this is LDVIRTFTN of an interface method that is part of a verifiable delegate creation sequence, + // RyuJIT is not going to use this value. + Debug.Assert(helperId == ReadyToRunHelperId.ResolveVirtualFunction); + pResult.exactContextNeedsRuntimeLookup = false; + pResult.codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ExternSymbol("NYI_LDVIRTFTN")); } else { diff --git a/src/JitInterface/src/CorInfoTypes.cs b/src/JitInterface/src/CorInfoTypes.cs index 53bb1f721..513def773 100644 --- a/src/JitInterface/src/CorInfoTypes.cs +++ b/src/JitInterface/src/CorInfoTypes.cs @@ -1021,6 +1021,10 @@ namespace Internal.JitInterface CORINFO_VIRTUALCALL_VTABLE }; + public enum CORINFO_VIRTUALCALL_NO_CHUNK : uint + { + Value = 0xFFFFFFFF, + } public unsafe struct CORINFO_CALL_INFO { diff --git a/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs b/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs index 52bc25701..212aa98b9 100644 --- a/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs +++ b/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs @@ -97,6 +97,11 @@ namespace ILCompiler return intrinsicMethod; } + public bool HasFixedSlotVTable(TypeDesc type) + { + return true; + } + public DelegateCreationInfo GetDelegateCtor(TypeDesc delegateType, MethodDesc target, bool followVirtualDispatch) { return DelegateCreationInfo.Create(delegateType, target, NodeFactory, followVirtualDispatch); diff --git a/src/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj b/src/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj index 5491c32c6..fa220b956 100644 --- a/src/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj +++ b/src/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj @@ -52,6 +52,7 @@ <NativeFormatCommonPath>..\..\Common\src\Internal\NativeFormat</NativeFormatCommonPath> </PropertyGroup> <ItemGroup Condition="'$(JitSupport)' == 'true'"> + <Compile Include="..\..\Common\src\TypeSystem\Common\CastingHelper.cs" /> <Compile Include="..\..\Common\src\TypeSystem\RuntimeDetermined\ArrayType.RuntimeDetermined.cs" /> <Compile Include="..\..\Common\src\TypeSystem\RuntimeDetermined\ByRefType.RuntimeDetermined.cs" /> <Compile Include="..\..\Common\src\TypeSystem\RuntimeDetermined\DefType.RuntimeDetermined.cs" /> diff --git a/src/packaging/packages.targets b/src/packaging/packages.targets index 3695f21a9..c76fd287e 100644 --- a/src/packaging/packages.targets +++ b/src/packaging/packages.targets @@ -26,7 +26,7 @@ <CoreFxNuPkgRid Condition="'$(OSGroup)'=='OSX'">osx-x64</CoreFxNuPkgRid> <CoreFxNuPkgRid Condition="'$(CoreFxNuPkgRid)'==''">$(NuPkgRid)</CoreFxNuPkgRid> - <JitPackageVersion>2.1.0-preview1-25406-04</JitPackageVersion> + <JitPackageVersion>2.1.0-preview1-25412-03</JitPackageVersion> <JitNuPkgRid Condition="'$(OSGroup)'=='Windows_NT'">win-x64</JitNuPkgRid> <JitNuPkgRid Condition="'$(OSGroup)'=='OSX'">osx-x64</JitNuPkgRid> <JitNuPkgRid Condition="'$(OSGroup)'=='Linux'">linux-x64</JitNuPkgRid> diff --git a/src/packaging/ryujit/project.json b/src/packaging/ryujit/project.json index fc003705f..62e1aa26b 100644 --- a/src/packaging/ryujit/project.json +++ b/src/packaging/ryujit/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.NETCore.Jit": "2.1.0-preview1-25406-04" + "Microsoft.NETCore.Jit": "2.1.0-preview1-25412-03" }, "frameworks": { "netcoreapp2.0": { } diff --git a/tests/src/Simple/Generics/Generics.cs b/tests/src/Simple/Generics/Generics.cs index 213400efe..6ad140ae8 100644 --- a/tests/src/Simple/Generics/Generics.cs +++ b/tests/src/Simple/Generics/Generics.cs @@ -820,7 +820,8 @@ class Program new DerivedClass2<string>().GVMethod2<string>("string", "string2"); new DerivedClass2<string>().GVMethod3<string>("string", "string2"); new DerivedClass2<string>().GVMethod4<string>("string", "string2"); - ((IFace<string>)new BaseClass<string>()).IFaceMethod1("string"); + Func<IFace<string>> f = () => new BaseClass<string>(); // Hack to prevent devirtualization + f().IFaceMethod1("string"); ((IFace<string>)new BaseClass<string>()).IFaceGVMethod1<string>("string1", "string2"); MethodInfo m1 = typeof(BaseClass<string>).GetTypeInfo().GetDeclaredMethod("Method1"); |