From 30a641bc79f832db116cd817a8c6508547555999 Mon Sep 17 00:00:00 2001 From: Konstantin Baladurin Date: Mon, 20 Aug 2018 19:24:46 +0300 Subject: [PATCH] CppCodeGen: implement shared generics and support generic virtual methods --- .../BlockReflectionTypeMapNode.cs | 2 +- .../DependencyAnalysis/CanonicalEETypeNode.cs | 3 +- .../ExactMethodInstantiationsNode.cs | 2 +- .../ExternalReferencesTableNode.cs | 17 +- .../FatFunctionPointerNode.cs | 2 + .../GenericMethodsHashtableNode.cs | 2 +- .../GenericMethodsTemplateMap.cs | 2 +- .../GenericTypesHashtableNode.cs | 2 +- .../GenericVirtualMethodTableNode.cs | 2 +- .../InterfaceGenericVirtualMethodTableNode.cs | 2 +- .../DependencyAnalysis/MetadataNode.cs | 2 +- .../NativeLayoutInfoNode.cs | 2 +- .../NativeLayoutSignatureNode.cs | 2 + .../NecessaryCanonicalEETypeNode.cs | 3 +- .../ReadyToRunGenericHelperNode.cs | 5 + .../DependencyAnalysis/TypeMetadataMapNode.cs | 2 +- .../TypeThreadStaticIndexNode.cs | 4 +- .../src/Compiler/CppCodegenCompilation.cs | 17 +- .../src/Compiler/CppNodeMangler.cs | 3 +- .../CppCodegenNodeFactory.cs | 8 + .../DependencyAnalysis/CppMethodCodeNode.cs | 2 + .../src/CppCodeGen/CppWriter.cs | 1131 ++++++++++++-- .../src/CppCodeGen/EvaluationStack.cs | 13 + .../src/CppCodeGen/ILToCppImporter.cs | 1318 ++++++++++++++--- src/ILCompiler/src/Program.cs | 4 +- .../TypeLoader/ExternalReferencesTable.cs | 23 +- 26 files changed, 2190 insertions(+), 385 deletions(-) diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs index b9ccd7b07b9..d16c63afe2b 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs @@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis /// /// Represents a hashtable of all type blocked from reflection. /// - internal sealed class BlockReflectionTypeMapNode : ObjectNode, ISymbolDefinitionNode + public sealed class BlockReflectionTypeMapNode : ObjectNode, ISymbolDefinitionNode { private ObjectAndOffsetSymbolNode _endSymbol; private ExternalReferencesTableNode _externalReferences; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs index 945e49c39cf..1c6e84c2d1e 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs @@ -19,14 +19,13 @@ namespace ILCompiler.DependencyAnalysis /// Similarly, the dependencies that we track for canonicl type instantiations are minimal, and are just the ones used /// by the dynamic type loader /// - internal sealed class CanonicalEETypeNode : EETypeNode + public sealed class CanonicalEETypeNode : EETypeNode { public CanonicalEETypeNode(NodeFactory factory, TypeDesc type) : base(factory, type) { Debug.Assert(!type.IsCanonicalDefinitionType(CanonicalFormKind.Any)); Debug.Assert(type.IsCanonicalSubtype(CanonicalFormKind.Any)); Debug.Assert(type == type.ConvertToCanonForm(CanonicalFormKind.Specific)); - Debug.Assert(!type.IsMdArray); } public override bool StaticDependenciesAreComputed => true; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs index b4bf6659e9f..57177b0d855 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs @@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis /// /// Hashtable of all exact (non-canonical) generic method instantiations compiled in the module. /// - internal sealed class ExactMethodInstantiationsNode : ObjectNode, ISymbolDefinitionNode + public sealed class ExactMethodInstantiationsNode : ObjectNode, ISymbolDefinitionNode { private ObjectAndOffsetSymbolNode _endSymbol; private ExternalReferencesTableNode _externalReferences; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExternalReferencesTableNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExternalReferencesTableNode.cs index d37a4be9529..c4c91c4dfa2 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExternalReferencesTableNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExternalReferencesTableNode.cs @@ -97,14 +97,8 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) foreach (SymbolAndDelta symbolAndDelta in _insertedSymbols) { - if (factory.Target.Abi == TargetAbi.CoreRT) + if (factory.Target.Abi == TargetAbi.ProjectN) { - // TODO: set low bit if the linkage of the symbol is IAT_PVALUE. - builder.EmitReloc(symbolAndDelta.Symbol, RelocType.IMAGE_REL_BASED_RELPTR32, symbolAndDelta.Delta); - } - else - { - Debug.Assert(factory.Target.Abi == TargetAbi.ProjectN); int delta = symbolAndDelta.Delta; if (symbolAndDelta.Symbol.RepresentsIndirectionCell) { @@ -112,6 +106,15 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) } builder.EmitReloc(symbolAndDelta.Symbol, RelocType.IMAGE_REL_BASED_ADDR32NB, delta); } + else if (factory.Target.SupportsRelativePointers) + { + // TODO: set low bit if the linkage of the symbol is IAT_PVALUE. + builder.EmitReloc(symbolAndDelta.Symbol, RelocType.IMAGE_REL_BASED_RELPTR32, symbolAndDelta.Delta); + } + else + { + builder.EmitPointerReloc(symbolAndDelta.Symbol, symbolAndDelta.Delta); + } } _endSymbol.SetSymbolOffset(builder.CountBytes); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/FatFunctionPointerNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/FatFunctionPointerNode.cs index e54f189198a..c7c68651843 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/FatFunctionPointerNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/FatFunctionPointerNode.cs @@ -19,6 +19,8 @@ public class FatFunctionPointerNode : ObjectNode, IMethodNode, ISymbolDefinition { private bool _isUnboxingStub; + public bool IsUnboxingStub => _isUnboxingStub; + public FatFunctionPointerNode(MethodDesc methodRepresented, bool isUnboxingStub) { // We should not create these for methods that don't have a canonical method body diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs index efbe77897a4..cf83c65c8aa 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs @@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis /// /// Represents a hashtable of all compiled generic method instantiations /// - internal sealed class GenericMethodsHashtableNode : ObjectNode, ISymbolDefinitionNode + public sealed class GenericMethodsHashtableNode : ObjectNode, ISymbolDefinitionNode { private ObjectAndOffsetSymbolNode _endSymbol; private ExternalReferencesTableNode _externalReferences; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs index c4a7432195b..b03a4564996 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs @@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis /// /// Hashtable of all generic method templates used by the TypeLoader at runtime /// - internal sealed class GenericMethodsTemplateMap : ObjectNode, ISymbolDefinitionNode + public sealed class GenericMethodsTemplateMap : ObjectNode, ISymbolDefinitionNode { private ObjectAndOffsetSymbolNode _endSymbol; private ExternalReferencesTableNode _externalReferences; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs index 0bf0f385004..7645ffc987f 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs @@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis /// /// Represents a hashtable of all compiled generic type instantiations /// - internal sealed class GenericTypesHashtableNode : ObjectNode, ISymbolDefinitionNode + public sealed class GenericTypesHashtableNode : ObjectNode, ISymbolDefinitionNode { private ObjectAndOffsetSymbolNode _endSymbol; private ExternalReferencesTableNode _externalReferences; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs index 77b0ee180b2..08bd8b7b1cd 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs @@ -15,7 +15,7 @@ namespace ILCompiler.DependencyAnalysis /// /// Represents a map of generic virtual method implementations. /// - internal sealed class GenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode + public sealed class GenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode { private ObjectAndOffsetSymbolNode _endSymbol; private ExternalReferencesTableNode _externalReferences; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs index 38fc2bd52f2..75e12016ccf 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs @@ -15,7 +15,7 @@ namespace ILCompiler.DependencyAnalysis /// /// Represents a map between reflection metadata and generated method bodies. /// - internal sealed class InterfaceGenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode + public sealed class InterfaceGenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode { private ObjectAndOffsetSymbolNode _endSymbol; private ExternalReferencesTableNode _externalReferences; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs index fda760c8ce6..ba1e97e3a8f 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs @@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis /// Represents a blob of native metadata describing assemblies, the types in them, and their members. /// The data is used at runtime to e.g. support reflection. /// - internal sealed class MetadataNode : ObjectNode, ISymbolDefinitionNode + public sealed class MetadataNode : ObjectNode, ISymbolDefinitionNode { ObjectAndOffsetSymbolNode _endSymbol; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs index 2b61d0ff485..570260af9bc 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs @@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis /// /// Native layout info blob. /// - internal sealed class NativeLayoutInfoNode : ObjectNode, ISymbolDefinitionNode + public sealed class NativeLayoutInfoNode : ObjectNode, ISymbolDefinitionNode { private ObjectAndOffsetSymbolNode _endSymbol; private ExternalReferencesTableNode _externalReferences; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutSignatureNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutSignatureNode.cs index f4a0044ea76..935daacc790 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutSignatureNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutSignatureNode.cs @@ -21,6 +21,8 @@ public class NativeLayoutSignatureNode : ObjectNode, ISymbolDefinitionNode private Utf8String _identityPrefix; private NativeLayoutSavedVertexNode _nativeSignature; + public TypeSystemEntity Identity => _identity; + public NativeLayoutSignatureNode(NativeLayoutSavedVertexNode nativeSignature, TypeSystemEntity identity, Utf8String identityPrefix) { _nativeSignature = nativeSignature; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs index a55b62860ad..8515b69ef5a 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs @@ -12,14 +12,13 @@ namespace ILCompiler.DependencyAnalysis /// /// The node is used in ProjectX to represent a canonical type that does not have a vtable. /// - internal sealed class NecessaryCanonicalEETypeNode : EETypeNode + public sealed class NecessaryCanonicalEETypeNode : EETypeNode { public NecessaryCanonicalEETypeNode(NodeFactory factory, TypeDesc type) : base(factory, type) { Debug.Assert(!type.IsCanonicalDefinitionType(CanonicalFormKind.Any)); Debug.Assert(type.IsCanonicalSubtype(CanonicalFormKind.Any)); Debug.Assert(type == type.ConvertToCanonForm(CanonicalFormKind.Specific)); - Debug.Assert(!type.IsMdArray); } protected override ISymbolNode GetBaseTypeNode(NodeFactory factory) diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs index f68ccbf0a5d..e3065acfe89 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs @@ -20,6 +20,11 @@ public abstract partial class ReadyToRunGenericHelperNode : AssemblyStubNode, IN protected TypeSystemEntity _dictionaryOwner; protected GenericLookupResult _lookupSignature; + public ReadyToRunHelperId Id => _id; + public Object Target => _target; + public TypeSystemEntity DictionaryOwner => _dictionaryOwner; + public GenericLookupResult LookupSignature => _lookupSignature; + public ReadyToRunGenericHelperNode(NodeFactory factory, ReadyToRunHelperId helperId, object target, TypeSystemEntity dictionaryOwner) { _id = helperId; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs index 469d86dd5bc..13c89dba7ef 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs @@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis /// /// Represents a map between EETypes and metadata records within the . /// - internal sealed class TypeMetadataMapNode : ObjectNode, ISymbolDefinitionNode + public sealed class TypeMetadataMapNode : ObjectNode, ISymbolDefinitionNode { private ObjectAndOffsetSymbolNode _endSymbol; private ExternalReferencesTableNode _externalReferences; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeThreadStaticIndexNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeThreadStaticIndexNode.cs index 2c20841bb25..44ba5283526 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeThreadStaticIndexNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeThreadStaticIndexNode.cs @@ -10,7 +10,7 @@ namespace ILCompiler.DependencyAnalysis /// /// Represents a node containing information necessary at runtime to locate type's thread static base. /// - internal class TypeThreadStaticIndexNode : ObjectNode, ISymbolDefinitionNode + public class TypeThreadStaticIndexNode : ObjectNode, ISymbolDefinitionNode { private MetadataType _type; @@ -67,6 +67,8 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) return objData.ToObjectData(); } + public MetadataType Type => _type; + public override int ClassCode => -149601250; public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilation.cs b/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilation.cs index 61e8c8d594d..291612b8188 100644 --- a/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilation.cs +++ b/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilation.cs @@ -53,9 +53,22 @@ protected override void CompileInternal(string outputFile, ObjectDumper dumper) protected override void ComputeDependencyNodeDependencies(List> obj) { - foreach (CppMethodCodeNode methodCodeNodeNeedingCode in obj) + foreach (var dependency in obj) { - _cppWriter.CompileMethod(methodCodeNodeNeedingCode); + var methodCodeNodeNeedingCode = dependency as CppMethodCodeNode; + if (methodCodeNodeNeedingCode == null) + { + // To compute dependencies of the shadow method that tracks dictionary + // dependencies we need to ensure there is code for the canonical method body. + var dependencyMethod = (ShadowConcreteMethodNode)dependency; + methodCodeNodeNeedingCode = (CppMethodCodeNode)dependencyMethod.CanonicalMethodNode; + } + + // We might have already compiled this method. + if (methodCodeNodeNeedingCode.StaticDependenciesAreComputed) + continue; + + _cppWriter.CompileMethod((CppMethodCodeNode)methodCodeNodeNeedingCode); } } diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/CppNodeMangler.cs b/src/ILCompiler.CppCodeGen/src/Compiler/CppNodeMangler.cs index b4a01d6b2a1..ad2813eb4bc 100644 --- a/src/ILCompiler.CppCodeGen/src/Compiler/CppNodeMangler.cs +++ b/src/ILCompiler.CppCodeGen/src/Compiler/CppNodeMangler.cs @@ -47,7 +47,8 @@ public sealed override string TypeGenericDictionary(TypeDesc type) public sealed override string MethodGenericDictionary(MethodDesc method) { - return GenericDictionaryNamePrefix + NameMangler.GetMangledMethodName(method); + return GenericDictionaryNamePrefix + NameMangler.GetMangledTypeName(method.OwningType) + + "_" + NameMangler.GetMangledMethodName(method); } } } diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs index d282e1f270f..0a558175ded 100644 --- a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs +++ b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs @@ -28,6 +28,14 @@ public CppCodegenNodeFactory(CompilerTypeSystemContext context, CompilationModul protected override IMethodNode CreateMethodEntrypointNode(MethodDesc method) { + if (method.IsInternalCall) + { + if (method.IsArrayAddressMethod()) + { + return MethodEntrypoint(((ArrayType)method.OwningType).GetArrayMethod(ArrayMethodKind.AddressWithHiddenArg)); + } + } + if (CompilationModuleGroup.ContainsMethodBody(method, false)) { return new CppMethodCodeNode(method); diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppMethodCodeNode.cs b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppMethodCodeNode.cs index 49f610ef456..b6c9737915b 100644 --- a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppMethodCodeNode.cs +++ b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppMethodCodeNode.cs @@ -70,6 +70,8 @@ public override IEnumerable GetStaticDependencies(NodeFacto foreach (Object node in _dependencies) dependencies.Add(node, "CPP code "); + CodeBasedDependencyAlgorithm.AddDependenciesDueToMethodCodePresence(ref dependencies, factory, _method); + return dependencies; } diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs index c37a53382e7..7899c267423 100644 --- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs +++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Text; using System.Collections.Generic; using System.IO; using System.Linq; @@ -78,6 +79,8 @@ private string GetMangledTypeName(TypeDesc type) public string GetCppSignatureTypeName(TypeDesc type) { + type = ConvertToCanonFormIfNecessary(type, CanonicalFormKind.Specific); + string mangledName; if (_cppSignatureNames.TryGetValue(type, out mangledName)) return mangledName; @@ -125,7 +128,13 @@ private IEnumerable GetParameterNamesForMethod(MethodDesc method) return null; } - public void AppendCppMethodDeclaration(CppGenerationBuffer sb, MethodDesc method, bool implementation, string externalMethodName = null, MethodSignature methodSignature = null, string cppMethodName = null) + public string GetCppHiddenParam() + { + return "___hidden"; + } + + public void AppendCppMethodDeclaration(CppGenerationBuffer sb, MethodDesc method, bool implementation, string externalMethodName = null, + MethodSignature methodSignature = null, string cppMethodName = null, bool isUnboxingStub = false) { if (methodSignature == null) methodSignature = method.Signature; @@ -159,14 +168,31 @@ public void AppendCppMethodDeclaration(CppGenerationBuffer sb, MethodDesc method } } sb.Append("("); + bool hasThis = !methodSignature.IsStatic; + bool hasHiddenParam = false; int argCount = methodSignature.Length; + + int hiddenArgIdx = -1; + int thisArgIdx = -1; + int signatureArgOffset = 0; + int paramListOffset = 0; + if (hasThis) + { argCount++; + thisArgIdx++; + signatureArgOffset++; + } List parameterNames = null; if (method != null) { + if (isUnboxingStub) + hasHiddenParam = method.IsSharedByGenericInstantiations && + (method.HasInstantiation || method.Signature.IsStatic); + else + hasHiddenParam = method.RequiresInstArg(); IEnumerable parameters = GetParameterNamesForMethod(method); if (parameters != null) { @@ -182,43 +208,66 @@ public void AppendCppMethodDeclaration(CppGenerationBuffer sb, MethodDesc method } } - for (int i = 0; i < argCount; i++) + if (hasHiddenParam) { + argCount++; + hiddenArgIdx++; if (hasThis) + hiddenArgIdx++; + signatureArgOffset++; + paramListOffset++; + } + + for (int i = 0; i < argCount; i++) + { + if (i == thisArgIdx) { - if (i == 0) - { - var thisType = method.OwningType; - if (thisType.IsValueType) - thisType = thisType.MakeByRefType(); - sb.Append(GetCppSignatureTypeName(thisType)); - } - else - { - sb.Append(GetCppSignatureTypeName(methodSignature[i - 1])); - } + var thisType = method.OwningType; + if (thisType.IsValueType) + thisType = thisType.MakeByRefType(); + sb.Append(GetCppSignatureTypeName(thisType)); + } + else if (i == hiddenArgIdx) + { + sb.Append("void*"); } else { - sb.Append(GetCppSignatureTypeName(methodSignature[i])); + sb.Append(GetCppSignatureTypeName(methodSignature[i - signatureArgOffset])); } + if (implementation) { sb.Append(" "); - if (parameterNames != null) + if (i == hiddenArgIdx) { - sb.Append(SanitizeCppVarName(parameterNames[i])); + sb.Append(" "); + sb.Append(GetCppHiddenParam()); } else { - sb.Append("_a"); - sb.Append(i.ToStringInvariant()); + int idx; + if (i == thisArgIdx) + idx = i; + else + idx = i - paramListOffset; + + if (parameterNames != null) + { + sb.Append(SanitizeCppVarName(parameterNames[idx])); + } + else + { + sb.Append("_a"); + sb.Append(idx.ToStringInvariant()); + } } } if (i != argCount - 1) sb.Append(", "); } + sb.Append(")"); if (!implementation) sb.Append(";"); @@ -229,9 +278,18 @@ public void AppendCppMethodCallParamList(CppGenerationBuffer sb, MethodDesc meth var methodSignature = method.Signature; bool hasThis = !methodSignature.IsStatic; + bool hasHiddenParam = method.RequiresInstArg(); int argCount = methodSignature.Length; + + int hiddenArgIdx = -1; + int thisArgIdx = -1; + int paramListOffset = 0; + if (hasThis) + { argCount++; + thisArgIdx++; + } List parameterNames = null; IEnumerable parameters = GetParameterNamesForMethod(method); @@ -248,9 +306,18 @@ public void AppendCppMethodCallParamList(CppGenerationBuffer sb, MethodDesc meth } } + if (hasHiddenParam) + { + argCount++; + hiddenArgIdx++; + if (hasThis) + hiddenArgIdx++; + paramListOffset++; + } + for (int i = 0; i < argCount; i++) { - if(i == 0 && unbox) + if (i == thisArgIdx && unbox) { // Unboxing stubs only valid for non-static methods on value types System.Diagnostics.Debug.Assert(hasThis); @@ -261,20 +328,52 @@ public void AppendCppMethodCallParamList(CppGenerationBuffer sb, MethodDesc meth sb.Append("("); sb.Append(GetCppSignatureTypeName(thisType)); sb.Append(")((uint8_t*)("); + + if (parameterNames != null) + { + sb.Append(SanitizeCppVarName(parameterNames[i])); + } + else + { + sb.Append("_a"); + sb.Append(i.ToStringInvariant()); + } + + sb.Append(")+sizeof(void*))"); } - if (parameterNames != null) + else if (i == hiddenArgIdx) { - sb.Append(SanitizeCppVarName(parameterNames[i])); + bool unboxStubHasHiddenArg = method.IsSharedByGenericInstantiations && + (method.HasInstantiation || method.Signature.IsStatic); + + if (unbox && !unboxStubHasHiddenArg) + { + sb.Append("*(void**)"); + if (parameterNames != null) + sb.Append(SanitizeCppVarName(parameterNames[thisArgIdx])); + else + sb.Append("_a" + thisArgIdx); + } + else + { + sb.Append(GetCppHiddenParam()); + } } else { - sb.Append("_a"); - sb.Append(i.ToStringInvariant()); - } - if (i == 0 && hasThis && unbox) - { - sb.Append(")+sizeof(void*))"); + int idx = i - paramListOffset; + + if (parameterNames != null) + { + sb.Append(SanitizeCppVarName(parameterNames[idx])); + } + else + { + sb.Append("_a"); + sb.Append(idx.ToStringInvariant()); + } } + if (i != argCount - 1) sb.Append(", "); } @@ -316,6 +415,103 @@ public string GetCppMethodName(MethodDesc method) return _compilation.NameMangler.GetMangledMethodName(method).ToString(); } + public string GetCppReadyToRunGenericHelperNodeName(NodeFactory factory, ReadyToRunGenericHelperNode node) + { + if (node.DictionaryOwner is MethodDesc) + { + Utf8StringBuilder sb = new Utf8StringBuilder(); + MethodDesc method = (MethodDesc)node.DictionaryOwner; + + if (node is ReadyToRunGenericLookupFromDictionaryNode) + sb.Append("__GenericLookupFromDict_"); + else + sb.Append("__GenericLookupFromType_"); + + sb.Append(factory.NameMangler.GetMangledTypeName(method.OwningType)); + sb.Append("_"); + sb.Append(factory.NameMangler.GetMangledMethodName(method)); + sb.Append("_"); + + if (node.Id != ReadyToRunHelperId.DelegateCtor) + node.LookupSignature.AppendMangledName(factory.NameMangler, sb); + else + ((DelegateCreationInfo)node.Target).AppendMangledName(factory.NameMangler, sb); + + return sb.ToString().Replace("::", "_"); + } + + return node.GetMangledName(factory.NameMangler).Replace("::", "_"); + } + + public string GetCppRuntimeMethodHandleName(RuntimeMethodHandleNode node) + { + MethodDesc method = node.Method; + StringBuilder sb = new StringBuilder(); + + sb.Append("__RuntimeMethodHandle_"); + sb.Append(GetMangledTypeName(method.OwningType)); + sb.Append("_"); + sb.Append(GetCppMethodName(method)); + + return sb.ToString().Replace("::", "_"); + } + + private string GetCppNativeLayoutSignatureName(NodeFactory factory, NativeLayoutSignatureNode node) + { + if (node.Identity is MethodDesc) + { + MethodDesc method = node.Identity as MethodDesc; + StringBuilder sb = new StringBuilder(); + + sb.Append("__RMHSignature_"); + sb.Append(GetMangledTypeName(method.OwningType)); + sb.Append("_"); + sb.Append(GetCppMethodName(method)); + + return sb.ToString().Replace("::", "_"); + } + + return node.GetMangledName(factory.NameMangler).Replace("::", "_");; + } + + private string GetCppFatFunctionPointerNameForMethod(MethodDesc method, + bool isUnboxingStub = false) + { + StringBuilder sb = new StringBuilder(); + + sb.Append(isUnboxingStub ? "__fatunboxpointer_" : "__fatpointer_"); + sb.Append(GetMangledTypeName(method.OwningType)); + sb.Append("_"); + sb.Append(GetCppMethodName(method)); + + return sb.ToString().Replace("::", "_"); + } + + private string GetCppFatFunctionPointerName(FatFunctionPointerNode node) + { + return GetCppFatFunctionPointerNameForMethod(node.Method, node.IsUnboxingStub); + } + + public string GetCppSymbolNodeName(NodeFactory factory, ISymbolNode node) + { + if (node is RuntimeMethodHandleNode) + { + return GetCppRuntimeMethodHandleName(node as RuntimeMethodHandleNode); + } + else if (node is NativeLayoutSignatureNode) + { + return GetCppNativeLayoutSignatureName(factory, node as NativeLayoutSignatureNode); + } + else if (node is FatFunctionPointerNode) + { + return GetCppFatFunctionPointerName(node as FatFunctionPointerNode); + } + else + { + return node.GetMangledName(factory.NameMangler); + } + } + public string GetCppFieldName(FieldDesc field) { string name = _compilation.NameMangler.GetMangledFieldName(field).ToString(); @@ -327,11 +523,44 @@ public string GetCppFieldName(FieldDesc field) return name; } - public string GetCppStaticFieldName(FieldDesc field) + public string GetCppStaticsName(TypeDesc type, bool isGCStatic = false, bool isThreadStatic = false) { - TypeDesc type = field.OwningType; + string name; + if (isThreadStatic) + { + name = "threadStatics"; + } + else if (isGCStatic) + { + name = "gcStatics"; + } + else + { + name = "statics"; + } + string typeName = GetCppTypeName(type); - return typeName.Replace("::", "__") + "__" + _compilation.NameMangler.GetMangledFieldName(field); + return typeName.Replace("::", "_") + "_" + name; + } + + public string GetCppStaticsTypeName(TypeDesc type, bool isGCStatic = false, bool isThreadStatic = false) + { + string name; + if (isThreadStatic) + { + name = "ThreadStatics"; + } + else if (isGCStatic) + { + name = "GCStatics"; + } + else + { + name = "Statics"; + } + + string typeName = GetCppTypeName(type); + return typeName.Replace("::", "_") + "_" + name; } public string SanitizeCppVarName(string varName) @@ -479,11 +708,14 @@ private TextWriter Out private StreamWriter _out; private Dictionary> _methodLists; + private HashSet _typesWithCctor; + + private Dictionary _statics; + private Dictionary _gcStatics; + private Dictionary _threadStatics; - private CppGenerationBuffer _statics; - private CppGenerationBuffer _gcStatics; - private CppGenerationBuffer _threadStatics; - private CppGenerationBuffer _gcThreadStatics; + private Dictionary, int> _methodNameAndSignatures = + new Dictionary, int>(); // Base classes and valuetypes has to be emitted before they are used. private HashSet _emittedTypes; @@ -530,7 +762,6 @@ private void OutputTypeFields(CppGenerationBuffer sb, TypeDesc t) sb.Append("struct {"); sb.Indent(); } - } foreach (var field in t.GetFields()) @@ -542,19 +773,39 @@ private void OutputTypeFields(CppGenerationBuffer sb, TypeDesc t) TypeDesc fieldType = GetFieldTypeOrPlaceholder(field); CppGenerationBuffer builder; - if (!fieldType.IsValueType) + + if (field.IsThreadStatic) { - builder = _gcStatics; + if (!_threadStatics.TryGetValue(t, out builder)) + { + builder = new CppGenerationBuffer(); + builder.Indent(); + _threadStatics[t] = builder; + } + } + else if (field.HasGCStaticBase) + { + if (!_gcStatics.TryGetValue(t, out builder)) + { + builder = new CppGenerationBuffer(); + builder.Indent(); + _gcStatics[t] = builder; + } } else { - // TODO: Valuetype statics with GC references - builder = _statics; + if (!_statics.TryGetValue(t, out builder)) + { + // TODO: Valuetype statics with GC references + builder = new CppGenerationBuffer(); + builder.Indent(); + _statics[t] = builder; + } } builder.AppendLine(); builder.Append(GetCppSignatureTypeName(fieldType)); builder.Append(" "); - builder.Append(GetCppStaticFieldName(field) + ";"); + builder.Append(GetCppFieldName(field) + ";"); } else { @@ -614,7 +865,7 @@ private void AppendSlotTypeDef(CppGenerationBuffer sb, MethodDesc method) AppendSignatureTypeDef(sb, "__slot__" + GetCppMethodName(method), methodSignature, thisArgument); } - internal void AppendSignatureTypeDef(CppGenerationBuffer sb, string name, MethodSignature methodSignature, TypeDesc thisArgument) + internal void AppendSignatureTypeDef(CppGenerationBuffer sb, string name, MethodSignature methodSignature, TypeDesc thisArgument, bool needsHiddenArg = false) { sb.AppendLine(); sb.Append("typedef "); @@ -624,25 +875,42 @@ internal void AppendSignatureTypeDef(CppGenerationBuffer sb, string name, Method sb.Append(")("); int argCount = methodSignature.Length; + + int hiddenArgIdx = -1; + int thisArgIdx = -1; + int signatureArgOffset = 0; + if (thisArgument != null) + { argCount++; - for (int i = 0; i < argCount; i++) + signatureArgOffset++; + thisArgIdx++; + } + + if (needsHiddenArg) { + argCount++; + hiddenArgIdx++; if (thisArgument != null) + hiddenArgIdx++; + signatureArgOffset++; + } + + for (int i = 0; i < argCount; i++) + { + if (i == thisArgIdx) { - if (i == 0) - { - sb.Append(GetCppSignatureTypeName(thisArgument)); - } - else - { - sb.Append(GetCppSignatureTypeName(methodSignature[i - 1])); - } + sb.Append(GetCppSignatureTypeName(thisArgument)); + } + else if (i == hiddenArgIdx) + { + sb.Append("void*"); } else { - sb.Append(GetCppSignatureTypeName(methodSignature[i])); + sb.Append(GetCppSignatureTypeName(methodSignature[i - signatureArgOffset])); } + if (i != argCount - 1) sb.Append(", "); } @@ -731,7 +999,7 @@ private String GetCodeForVirtualMethod(MethodDesc method, int slot) return sb.ToString(); } - private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory) + private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory, bool generateMethod = true, string structType = null) { // virtual slots var nodeData = node.GetData(factory, false); @@ -796,22 +1064,32 @@ private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory) } } - bool generateMethod = !(node is BlobNode); + generateMethod = generateMethod && !(node is BlobNode); + + string retType; + + if (node is EETypeNode) + retType = "MethodTable * "; + else if (node is RuntimeMethodHandleNode) + retType = "::System_Private_CoreLib::System::RuntimeMethodHandle "; + else + retType = "void * "; + + string mangledName = GetCppSymbolNodeName(factory, (ISymbolNode)node); - string pointerType = node is EETypeNode ? "MethodTable * " : "void* "; if (generateMethod) { - nodeCode.Append(pointerType); + nodeCode.Append(retType); if (node is EETypeNode) { nodeCode.Append(GetCppMethodDeclarationName((node as EETypeNode).Type, "__getMethodTable")); } else { - string mangledName = ((ISymbolNode)node).GetMangledName(factory.NameMangler); + // Rename nodes to avoid name clash with types + bool shouldReplaceNamespaceQualifier = node is GenericCompositionNode || node is EETypeOptionalFieldsNode || + node is SealedVTableNode || node is TypeGenericDictionaryNode || node is IndirectionNode || node is MethodGenericDictionaryNode; - // Rename generic composition and optional fields nodes to avoid name clash with types - bool shouldReplaceNamespaceQualifier = node is GenericCompositionNode || node is EETypeOptionalFieldsNode || node is SealedVTableNode; nodeCode.Append(shouldReplaceNamespaceQualifier ? mangledName.Replace("::", "_") : mangledName); } nodeCode.Append("()"); @@ -823,9 +1101,18 @@ private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory) } else { - nodeCode.Append("extern \"C\" "); + if (node is BlobNode) + nodeCode.Append("extern \"C\" "); } - nodeCode.Append("struct {"); + nodeCode.Append("struct "); + + if (structType != null) + { + nodeCode.Append(structType); + nodeCode.Append(" "); + } + + nodeCode.Append("{"); nodeCode.AppendLine(); nodeCode.Append(GetCodeForNodeStruct(nodeDataSections, node)); @@ -835,7 +1122,8 @@ private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory) if (generateMethod) nodeCode.Append("} mt = {"); else - nodeCode.Append(" } " + ((ISymbolNode)node).GetMangledName(factory.NameMangler) + " = {"); + nodeCode.Append(" } " + mangledName.Replace("::", "_") + " = {"); + nodeCode.Append(GetCodeForNodeData(nodeDataSections, relocs, nodeData.Data, node, offset, factory)); nodeCode.Append("};"); @@ -843,9 +1131,21 @@ private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory) if (generateMethod) { nodeCode.AppendLine(); - nodeCode.Append("return ( "); - nodeCode.Append(pointerType); - nodeCode.Append(")&mt;"); + + if (node is RuntimeMethodHandleNode) + { + nodeCode.Append(retType); + nodeCode.Append(" r = {(intptr_t)&mt};"); + nodeCode.AppendLine(); + nodeCode.Append("return r;"); + } + else + { + nodeCode.Append("return ( "); + nodeCode.Append(retType); + nodeCode.Append(")&mt;"); + } + nodeCode.Exdent(); nodeCode.AppendLine(); nodeCode.Append("}"); @@ -893,9 +1193,17 @@ private String GetCodeForReloc(Relocation reloc, DependencyNode node, NodeFactor relocCode.Append("(void*)&"); relocCode.Append(GetCppMethodDeclarationName(method.Method.OwningType, GetCppMethodName(method.Method), false)); } - else if (reloc.Target is EETypeNode && node is EETypeNode) + else if (reloc.Target is EETypeNode && + (node is EETypeNode || + node is IndirectionNode || + node is GenericCompositionNode || + node is TypeGenericDictionaryNode || + node is MethodGenericDictionaryNode || + node is ExternalReferencesTableNode)) { - relocCode.Append(GetCppMethodDeclarationName((reloc.Target as EETypeNode).Type, "__getMethodTable", false)); + var type = (reloc.Target as EETypeNode).Type; + + relocCode.Append(GetCppMethodDeclarationName(type, "__getMethodTable", false)); relocCode.Append("()"); } // Node is either an non-emitted type or a generic composition - both are ignored for CPP codegen @@ -903,26 +1211,112 @@ private String GetCodeForReloc(Relocation reloc, DependencyNode node, NodeFactor reloc.Target is InterfaceDispatchMapNode || reloc.Target is EETypeOptionalFieldsNode || reloc.Target is GenericCompositionNode || - reloc.Target is SealedVTableNode + reloc.Target is SealedVTableNode || + reloc.Target is TypeGenericDictionaryNode || + reloc.Target is MethodGenericDictionaryNode || + reloc.Target is IndirectionNode || + reloc.Target is GenericVirtualMethodTableNode || + reloc.Target is InterfaceGenericVirtualMethodTableNode || + reloc.Target is RuntimeMethodHandleNode || + reloc.Target is NativeLayoutSignatureNode || + reloc.Target is ExactMethodInstantiationsNode || + reloc.Target is GenericMethodsHashtableNode || + reloc.Target is NativeLayoutInfoNode || + reloc.Target is MetadataNode || + reloc.Target is BlockReflectionTypeMapNode || + reloc.Target is ExternalReferencesTableNode || + reloc.Target is GenericTypesTemplateMap || + reloc.Target is GenericMethodsTemplateMap || + reloc.Target is GenericTypesHashtableNode || + reloc.Target is TypeMetadataMapNode || + reloc.Target is FatFunctionPointerNode ) && !(reloc.Target as ObjectNode).ShouldSkipEmittingObjectNode(factory)) { - string mangledTargetName = reloc.Target.GetMangledName(factory.NameMangler); - bool shouldReplaceNamespaceQualifier = reloc.Target is GenericCompositionNode || reloc.Target is EETypeOptionalFieldsNode || reloc.Target is SealedVTableNode; + string mangledTargetName = GetCppSymbolNodeName(factory, reloc.Target); + + bool shouldReplaceNamespaceQualifier = reloc.Target is GenericCompositionNode || reloc.Target is EETypeOptionalFieldsNode || + reloc.Target is SealedVTableNode || reloc.Target is TypeGenericDictionaryNode || reloc.Target is IndirectionNode || + reloc.Target is MethodGenericDictionaryNode; + + bool shouldUsePointer = reloc.Target is GenericCompositionNode || reloc.Target is TypeGenericDictionaryNode || + reloc.Target is MethodGenericDictionaryNode; + + bool isRuntimeMethodHandle = reloc.Target is RuntimeMethodHandleNode; + + if (shouldUsePointer) + relocCode.Append("(void *)&"); + else if (isRuntimeMethodHandle) + relocCode.Append("(void *)("); + relocCode.Append(shouldReplaceNamespaceQualifier ? mangledTargetName.Replace("::", "_") : mangledTargetName); - relocCode.Append("()"); + + if (!shouldUsePointer) + relocCode.Append("()"); + + if (isRuntimeMethodHandle) + relocCode.Append("._value)"); } else if (reloc.Target is ObjectAndOffsetSymbolNode && (reloc.Target as ObjectAndOffsetSymbolNode).Target is ArrayOfEmbeddedPointersNode) { relocCode.Append("dispatchMapModule"); } - else if(reloc.Target is CppUnboxingStubNode) + else if (reloc.Target is ObjectAndOffsetSymbolNode) + { + ObjectAndOffsetSymbolNode symbolNode = reloc.Target as ObjectAndOffsetSymbolNode; + + if ((symbolNode.Target is GenericVirtualMethodTableNode || + symbolNode.Target is InterfaceGenericVirtualMethodTableNode || + symbolNode.Target is ExactMethodInstantiationsNode || + symbolNode.Target is GenericMethodsHashtableNode || + symbolNode.Target is NativeLayoutInfoNode || + symbolNode.Target is MetadataNode || + symbolNode.Target is BlockReflectionTypeMapNode || + symbolNode.Target is ExternalReferencesTableNode || + symbolNode.Target is GenericTypesTemplateMap || + symbolNode.Target is GenericMethodsTemplateMap || + symbolNode.Target is GenericTypesHashtableNode || + symbolNode.Target is TypeMetadataMapNode + ) && !(symbolNode.Target as ObjectNode).ShouldSkipEmittingObjectNode(factory)) + { + relocCode.Append("((char *)"); + relocCode.Append((symbolNode.Target as ISymbolNode).GetMangledName(factory.NameMangler)); + relocCode.Append("()) + "); + relocCode.Append((symbolNode as ISymbolDefinitionNode).Offset.ToString()); + } + else + { + relocCode.Append("NULL"); + } + } + else if (reloc.Target is CppUnboxingStubNode) { var method = reloc.Target as CppUnboxingStubNode; relocCode.Append("(void*)&"); relocCode.Append(GetCppMethodDeclarationName(method.Method.OwningType, method.GetMangledName(factory.NameMangler), false)); } + else if (reloc.Target is GCStaticsNode) + { + var gcStaticNode = reloc.Target as GCStaticsNode; + + relocCode.Append("(void*)&"); + relocCode.Append(GetCppStaticsName(gcStaticNode.Type, true)); + } + else if (reloc.Target is NonGCStaticsNode) + { + var nonGcStaticNode = reloc.Target as NonGCStaticsNode; + + relocCode.Append("(void*)&"); + relocCode.Append(GetCppStaticsName(nonGcStaticNode.Type)); + } + else if (reloc.Target is TypeThreadStaticIndexNode) + { + var threadStaticIndexNode = reloc.Target as TypeThreadStaticIndexNode; + + relocCode.Append("(void*)&"); + relocCode.Append(GetCppStaticsName(threadStaticIndexNode.Type, true, true)); + } else { relocCode.Append("NULL"); @@ -973,6 +1367,7 @@ private static void AppendFormattedByteArray(CppGenerationBuffer sb, byte[] arra private void BuildMethodLists(IEnumerable nodes) { _methodLists = new Dictionary>(); + _typesWithCctor = new HashSet(); foreach (var node in nodes) { if (node is CppMethodCodeNode) @@ -982,6 +1377,9 @@ private void BuildMethodLists(IEnumerable nodes) var method = methodCodeNode.Method; var type = method.OwningType; + if (type.HasStaticConstructor && method.Equals(type.GetStaticConstructor())) + _typesWithCctor.Add(type); + List methodList; if (!_methodLists.TryGetValue(type, out methodList)) { @@ -1023,6 +1421,7 @@ public void OutputNodes(IEnumerable nodes, NodeFactory factory) CppGenerationBuffer typeDefinitions = new CppGenerationBuffer(); CppGenerationBuffer methodTables = new CppGenerationBuffer(); CppGenerationBuffer additionalNodes = new CppGenerationBuffer(); + CppGenerationBuffer indirectionNodes = new CppGenerationBuffer(); DependencyNodeIterator nodeIterator = new DependencyNodeIterator(nodes, factory); // Number of InterfaceDispatchMapNodes needs to be declared explicitly for Ubuntu and OSX @@ -1031,6 +1430,7 @@ public void OutputNodes(IEnumerable nodes, NodeFactory factory) dispatchPointers.Indent(); //RTR header needs to be declared after all modules have already been output + ReadyToRunHeaderNode rtrHeaderNode = null; string rtrHeader = string.Empty; // Iterate through nodes @@ -1042,8 +1442,69 @@ public void OutputNodes(IEnumerable nodes, NodeFactory factory) node is TypeManagerIndirectionNode || node is GenericCompositionNode || node is BlobNode || - node is SealedVTableNode) && !(node as ObjectNode).ShouldSkipEmittingObjectNode(factory)) - additionalNodes.Append(GetCodeForObjectNode(node as ObjectNode, factory)); + node is SealedVTableNode || + node is TypeGenericDictionaryNode || + node is MethodGenericDictionaryNode || + node is IndirectionNode || + node is GenericVirtualMethodTableNode || + node is InterfaceGenericVirtualMethodTableNode || + node is RuntimeMethodHandleNode || + node is NativeLayoutSignatureNode || + node is ExactMethodInstantiationsNode || + node is GenericMethodsHashtableNode || + node is NativeLayoutInfoNode || + node is MetadataNode || + node is BlockReflectionTypeMapNode || + node is ExternalReferencesTableNode || + node is GenericTypesTemplateMap || + node is GenericMethodsTemplateMap || + node is GenericTypesHashtableNode || + node is TypeMetadataMapNode || + node is FatFunctionPointerNode + ) && !(node as ObjectNode).ShouldSkipEmittingObjectNode(factory)) + { + if (node is IndirectionNode) + { + indirectionNodes.Append(GetCodeForObjectNode(node as ObjectNode, factory)); + } + else + { + bool shouldUsePointer = node is GenericCompositionNode || node is TypeGenericDictionaryNode || + node is MethodGenericDictionaryNode; + + if (shouldUsePointer) + { + string varName = GetCppSymbolNodeName(factory, (ISymbolNode)node).Replace("::", "_"); + string structType = "T_" + varName; + + additionalNodes.Append(GetCodeForObjectNode(node as ObjectNode, factory, false, structType)); + + forwardDefinitions.AppendLine(); + forwardDefinitions.Append("extern struct "); + forwardDefinitions.Append(structType); + forwardDefinitions.Append(" "); + forwardDefinitions.Append(varName); + forwardDefinitions.Append(";"); + } + else + { + additionalNodes.Append(GetCodeForObjectNode(node as ObjectNode, factory)); + } + } + + if (node is NativeLayoutSignatureNode || + node is RuntimeMethodHandleNode || + node is FatFunctionPointerNode) + { + forwardDefinitions.AppendLine(); + if (node is RuntimeMethodHandleNode) + forwardDefinitions.Append("::System_Private_CoreLib::System::RuntimeMethodHandle "); + else + forwardDefinitions.Append("void * "); + forwardDefinitions.Append(GetCppSymbolNodeName(factory, (ISymbolNode)node)); + forwardDefinitions.Append("();"); + } + } else if (node is ArrayOfEmbeddedPointersNode dispatchMap) { var dispatchMapData = dispatchMap.GetData(factory, false); @@ -1059,16 +1520,30 @@ node is BlobNode || } } else if (node is ReadyToRunHeaderNode) - rtrHeader = GetCodeForReadyToRunHeader(node as ReadyToRunHeaderNode, factory); + rtrHeaderNode = node as ReadyToRunHeaderNode; + else if (node is ReadyToRunGenericHelperNode) + additionalNodes.Append(GetCodeForReadyToRunGenericHelper(node as ReadyToRunGenericHelperNode, factory)); } + rtrHeader = GetCodeForReadyToRunHeader(rtrHeaderNode, factory); + dispatchPointers.AppendLine(); dispatchPointers.Exdent(); WriteForwardDefinitions(); + Out.Write(forwardDefinitions.ToString()); + Out.Write(typeDefinitions.ToString()); + OutputStaticsCode(_statics); + + OutputStaticsCode(_gcStatics, true); + + OutputStaticsCode(_threadStatics, true, true); + + Out.Write(indirectionNodes.ToString()); + Out.Write(additionalNodes.ToString()); Out.Write(methodTables.ToString()); @@ -1224,9 +1699,42 @@ private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenera if (nodeType.IsDefType && !nodeType.IsGenericDefinition) { OutputTypeFields(typeDefinitions, nodeType); + + if (nodeType.HasStaticConstructor) + { + MethodDesc cctor = nodeType.GetStaticConstructor().GetCanonMethodTarget(CanonicalFormKind.Specific); + + if (_typesWithCctor.Contains(cctor.OwningType)) + { + CppGenerationBuffer staticsBuffer; + + if (!_statics.TryGetValue(nodeType, out staticsBuffer)) + { + staticsBuffer = new CppGenerationBuffer(); + staticsBuffer.Indent(); + _statics[nodeType] = staticsBuffer; + } + + staticsBuffer.AppendLine(); + staticsBuffer.Append("bool __cctor_has_run;"); + staticsBuffer.AppendLine(); + + if (cctor.RequiresInstArg()) + { + staticsBuffer.Append("void (*__cctor)(void *);"); + staticsBuffer.AppendLine(); + staticsBuffer.Append("void *__ctx;"); + } + else + { + staticsBuffer.Append("void (*__cctor)();"); + } + } + } } - if (typeNode is ConstructedEETypeNode) + if ((typeNode is ConstructedEETypeNode || typeNode is CanonicalEETypeNode || + typeNode is NecessaryCanonicalEETypeNode) && nodeType is DefType) { DefType closestDefType = nodeType.GetClosestDefType(); @@ -1246,12 +1754,6 @@ private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenera } } - if (nodeType.HasStaticConstructor) - { - _statics.AppendLine(); - _statics.Append("bool __cctor_" + GetCppTypeName(nodeType).Replace("::", "__") + ";"); - } - List methodList; if (_methodLists.TryGetValue(nodeType, out methodList)) { @@ -1260,7 +1762,7 @@ private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenera typeDefinitions.AppendLine(); AppendCppMethodDeclaration(typeDefinitions, m, false); typeDefinitions.AppendLine(); - AppendCppMethodDeclaration(typeDefinitions, m, false, null, null, CppUnboxingStubNode.GetMangledName(factory.NameMangler, m)); + AppendCppMethodDeclaration(typeDefinitions, m, false, null, null, CppUnboxingStubNode.GetMangledName(factory.NameMangler, m), true); } } @@ -1338,6 +1840,359 @@ private String GetCodeForReadyToRunHeader(ReadyToRunHeaderNode headerNode, NodeF return rtrHeader.ToString(); } + private void OutputCodeForTriggerCctor(CppGenerationBuffer sb, TypeDesc type, + string staticsBaseVarName, string staticsVarName) + { + type = type.ConvertToCanonForm(CanonicalFormKind.Specific); + MethodDesc cctor = type.GetStaticConstructor(); + + sb.Append(GetCppStaticsTypeName(type)); + sb.Append(" *"); + sb.Append(staticsVarName); + sb.Append(" = "); + sb.Append("("); + sb.Append(GetCppStaticsTypeName(type)); + sb.Append("*)"); + sb.Append(staticsBaseVarName); + sb.Append(";"); + sb.AppendLine(); + + sb.Append("if (!"); + sb.Append(staticsVarName); + sb.Append("->__cctor_has_run) {"); + sb.Indent(); + sb.AppendLine(); + + sb.Append(staticsVarName); + sb.Append("->__cctor_has_run = true;"); + sb.AppendLine(); + + sb.Append(staticsVarName); + sb.Append("->__cctor("); + + if (cctor.RequiresInstArg()) + { + sb.Append(staticsVarName); + sb.Append("->__ctx"); + } + + sb.Append(");"); + + sb.Exdent(); + sb.AppendLine(); + sb.Append("}"); + sb.AppendLine(); + } + + private void OutputCodeForDictionaryLookup(CppGenerationBuffer sb, NodeFactory factory, + ReadyToRunGenericHelperNode node, GenericLookupResult lookup, string ctxVarName, + string resVarName) + { + // Find the generic dictionary slot + int dictionarySlot = factory.GenericDictionaryLayout(node.DictionaryOwner).GetSlotForEntry(lookup); + + int offset = dictionarySlot * factory.Target.PointerSize; + + // Load the generic dictionary cell + sb.Append(resVarName); + sb.Append(" = *(void **)((intptr_t)"); + sb.Append(ctxVarName); + sb.Append(" + "); + sb.Append(offset); + sb.Append(");"); + sb.AppendLine(); + + switch (lookup.LookupResultReferenceType(factory)) + { + case GenericLookupResultReferenceType.Indirect: + { + sb.Append(resVarName); + sb.Append(" = *(void **)"); + sb.Append(resVarName); + sb.Append(";"); + sb.AppendLine(); + } + break; + + case GenericLookupResultReferenceType.ConditionalIndirect: + throw new NotImplementedException(); + + default: + break; + } + } + + private string GetCodeForReadyToRunGenericHelper(ReadyToRunGenericHelperNode node, NodeFactory factory) + { + CppGenerationBuffer sb = new CppGenerationBuffer(); + + string mangledName = GetCppReadyToRunGenericHelperNodeName(factory, node); + List argNames = new List(new string[] {"arg"}); + string ctxVarName = "ctx"; + string resVarName = "res"; + string retVarName = "ret"; + + string retType; + switch (node.Id) + { + case ReadyToRunHelperId.MethodHandle: + retType = "::System_Private_CoreLib::System::RuntimeMethodHandle"; + break; + case ReadyToRunHelperId.DelegateCtor: + retType = "void"; + break; + default: + retType = "void*"; + break; + } + + sb.AppendLine(); + sb.Append(retType); + sb.Append(" "); + sb.Append(mangledName); + sb.Append("("); + sb.Append("void *"); + sb.Append(argNames[0]); + + if (node.Id == ReadyToRunHelperId.DelegateCtor) + { + sb.Append(", "); + + DelegateCreationInfo target = (DelegateCreationInfo)node.Target; + MethodDesc constructor = target.Constructor.Method; + + bool isStatic = constructor.Signature.IsStatic; + + int argCount = constructor.Signature.Length; + if (!isStatic) + argCount++; + + int startIdx = argNames.Count; + for (int i = 0; i < argCount; i++) + { + string argName = $"arg{i + startIdx}"; + argNames.Add(argName); + + TypeDesc argType; + if (i == 0 && !isStatic) + { + argType = constructor.OwningType; + } + else + { + argType = constructor.Signature[i - (isStatic ? 0 : 1)]; + } + + sb.Append(GetCppSignatureTypeName(argType)); + sb.Append(" "); + sb.Append(argName); + + if (i != argCount - 1) + sb.Append(", "); + } + } + + sb.Append(")"); + + sb.AppendLine(); + sb.Append("{"); + sb.Indent(); + sb.AppendLine(); + + sb.Append("void *"); + sb.Append(ctxVarName); + sb.Append(";"); + sb.AppendLine(); + + sb.Append("void *"); + sb.Append(resVarName); + sb.Append(";"); + sb.AppendLine(); + + if (node is ReadyToRunGenericLookupFromTypeNode) + { + // Locate the VTable slot that points to the dictionary + int vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(factory, (TypeDesc)node.DictionaryOwner); + + int pointerSize = factory.Target.PointerSize; + int slotOffset = EETypeNode.GetVTableOffset(pointerSize) + (vtableSlot * pointerSize); + + // Load the dictionary pointer from the VTable + sb.Append(ctxVarName); + sb.Append(" = *(void **)((intptr_t)"); + sb.Append(argNames[0]); + sb.Append(" + "); + sb.Append(slotOffset.ToString()); + sb.Append(");"); + sb.AppendLine(); + } + else + { + sb.Append(ctxVarName); + sb.Append(" = "); + sb.Append(argNames[0]); + sb.Append(";"); + sb.AppendLine(); + } + + OutputCodeForDictionaryLookup(sb, factory, node, node.LookupSignature, ctxVarName, resVarName); + + switch (node.Id) + { + case ReadyToRunHelperId.GetNonGCStaticBase: + { + MetadataType target = (MetadataType)node.Target; + + if (target.HasStaticConstructor) + { + string staticsVarName = "statics"; + + OutputCodeForTriggerCctor(sb, target, resVarName, staticsVarName); + } + } + break; + + case ReadyToRunHelperId.GetGCStaticBase: + { + MetadataType target = (MetadataType)node.Target; + + if (target.HasStaticConstructor) + { + string staticsVarName = "statics"; + string nonGcStaticsBase = "nonGcBase"; + + sb.Append("void *"); + sb.Append(nonGcStaticsBase); + sb.Append(";"); + sb.AppendLine(); + + GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); + + OutputCodeForDictionaryLookup(sb, factory, node, nonGcRegionLookup, ctxVarName, nonGcStaticsBase); + + OutputCodeForTriggerCctor(sb, target, nonGcStaticsBase, staticsVarName); + } + } + break; + + case ReadyToRunHelperId.GetThreadStaticBase: + { + MetadataType target = (MetadataType)node.Target; + + if (target.HasStaticConstructor) + { + string staticsVarName = "statics"; + string nonGcStaticsBase = "nonGcBase"; + + sb.Append("void *"); + sb.Append(nonGcStaticsBase); + sb.Append(";"); + sb.AppendLine(); + + GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); + + OutputCodeForDictionaryLookup(sb, factory, node, nonGcRegionLookup, ctxVarName, nonGcStaticsBase); + + OutputCodeForTriggerCctor(sb, target, nonGcStaticsBase, staticsVarName); + } + } + break; + + case ReadyToRunHelperId.DelegateCtor: + { + DelegateCreationInfo target = (DelegateCreationInfo)node.Target; + MethodDesc constructor = target.Constructor.Method; + + sb.Append("if ("); + sb.Append(argNames[3]); + sb.Append(" == 0) {"); + sb.Append(argNames[3]); + sb.Append(" = ((intptr_t)"); + sb.Append(resVarName); + sb.Append(") + 0x2;};"); + sb.AppendLine(); + + sb.Append("::"); + sb.Append(GetCppMethodDeclarationName(constructor.OwningType, GetCppMethodName(constructor))); + sb.Append("("); + + for (int i = 1; i < argNames.Count; i++) + { + sb.Append(argNames[i]); + + if (i != argNames.Count - 1) + sb.Append(", "); + } + + sb.Append(");"); + sb.AppendLine(); + } + break; + + // These are all simple: just get the thing from the dictionary and we're done + case ReadyToRunHelperId.TypeHandle: + case ReadyToRunHelperId.MethodHandle: + case ReadyToRunHelperId.FieldHandle: + case ReadyToRunHelperId.MethodDictionary: + case ReadyToRunHelperId.MethodEntry: + case ReadyToRunHelperId.VirtualDispatchCell: + case ReadyToRunHelperId.DefaultConstructor: + break; + default: + throw new NotImplementedException(); + } + + if (node.Id != ReadyToRunHelperId.DelegateCtor) + { + sb.Append(retType); + sb.Append(" "); + sb.Append(retVarName); + sb.Append(" = "); + + if (node.Id == ReadyToRunHelperId.MethodHandle) + { + sb.Append("{"); + sb.Append("(intptr_t)"); + sb.Append(resVarName); + sb.Append("};"); + } + else + { + sb.Append(resVarName); + sb.Append(";"); + } + + sb.AppendLine(); + + sb.Append("return "); + sb.Append(retVarName); + sb.Append(";"); + } + + sb.Exdent(); + sb.AppendLine(); + sb.Append("}"); + sb.AppendLine(); + + return sb.ToString(); + } + + private int GetNameAndSignatureId(MethodDesc method) + { + var nameAndSignature = new Tuple(method.Name, method.Signature); + + int uniqueId; + + if (!_methodNameAndSignatures.TryGetValue(nameAndSignature, out uniqueId)) + { + uniqueId = _methodNameAndSignatures.Count; + + _methodNameAndSignatures[nameAndSignature] = uniqueId; + } + + return uniqueId; + } + private void OutputExternCSignatures() { var sb = new CppGenerationBuffer(); @@ -1366,7 +2221,7 @@ private void OutputUnboxingStubNode(CppUnboxingStubNode unboxingStubNode) CppGenerationBuffer sb = new CppGenerationBuffer(); sb.AppendLine(); - AppendCppMethodDeclaration(sb, unboxingStubNode.Method, true, null, null, unboxingStubNode.GetMangledName(_compilation.NameMangler)); + AppendCppMethodDeclaration(sb, unboxingStubNode.Method, true, null, null, unboxingStubNode.GetMangledName(_compilation.NameMangler), true); sb.AppendLine(); sb.Append("{"); sb.Indent(); @@ -1375,6 +2230,7 @@ private void OutputUnboxingStubNode(CppUnboxingStubNode unboxingStubNode) { sb.Append("return "); } + sb.Append("::"); sb.Append(GetCppMethodDeclarationName(unboxingStubNode.Method.OwningType, GetCppMethodName(unboxingStubNode.Method))); sb.Append("("); AppendCppMethodCallParamList(sb, unboxingStubNode.Method, true); @@ -1386,6 +2242,92 @@ private void OutputUnboxingStubNode(CppUnboxingStubNode unboxingStubNode) Out.Write(sb.ToString()); } + private void OutputStaticsCode(Dictionary statics, + bool isGCStatic = false, bool isThreadStatic = false) + { + CppGenerationBuffer sb = new CppGenerationBuffer(); + + foreach (var entry in statics) + { + TypeDesc t = entry.Key; + + sb.Append("struct "); + sb.Append(GetCppStaticsTypeName(t, isGCStatic, isThreadStatic)); + sb.Append(" {"); + sb.Append(entry.Value.ToString()); + sb.Exdent(); + sb.AppendLine(); + sb.Append("};"); + sb.AppendLine(); + + if (t.IsCanonicalSubtype(CanonicalFormKind.Any)) + continue; + + sb.Append(GetCppStaticsTypeName(t, isGCStatic, isThreadStatic)); + sb.Append(" "); + sb.Append(GetCppStaticsName(t, isGCStatic, isThreadStatic)); + + if (!isGCStatic && t.HasStaticConstructor) + { + MethodDesc cctor = t.GetStaticConstructor(); + MethodDesc canonCctor = cctor.GetCanonMethodTarget(CanonicalFormKind.Specific); + + if (_typesWithCctor.Contains(canonCctor.OwningType)) + { + sb.Append(" = {"); + sb.Indent(); + sb.AppendLine(); + + if (canonCctor.RequiresInstArg()) + { + sb.Append(".__cctor = (void (*)(void *)) *(void **)"); + sb.Append(GetCppFatFunctionPointerNameForMethod(cctor)); + sb.Append("(),"); + sb.Append(".__ctx = **(void***) (((intptr_t)"); + sb.Append(GetCppFatFunctionPointerNameForMethod(cctor)); + sb.Append("()) + sizeof(void*))"); + } + else + { + sb.Append(".__cctor = &"); + sb.Append(GetCppMethodDeclarationName(canonCctor.OwningType, GetCppMethodName(canonCctor))); + } + + sb.Exdent(); + sb.AppendLine(); + sb.Append("}"); + } + } + + sb.Append(";"); + sb.AppendLine(); + } + + Out.Write(sb.ToString()); + } + + public TypeDesc ConvertToCanonFormIfNecessary(TypeDesc type, CanonicalFormKind policy) + { + if (!type.IsCanonicalSubtype(CanonicalFormKind.Any)) + return type; + + if (type.IsPointer || type.IsByRef) + { + ParameterizedType parameterizedType = (ParameterizedType)type; + TypeDesc paramTypeConverted = ConvertToCanonFormIfNecessary(parameterizedType.ParameterType, policy); + if (paramTypeConverted == parameterizedType.ParameterType) + return type; + + if (type.IsPointer) + return _compilation.TypeSystemContext.GetPointerType(paramTypeConverted); + + if (type.IsByRef) + return _compilation.TypeSystemContext.GetByRefType(paramTypeConverted); + } + + return type.ConvertToCanonForm(policy); + } + public void OutputCode(IEnumerable nodes, NodeFactory factory) { BuildMethodLists(nodes); @@ -1394,29 +2336,12 @@ public void OutputCode(IEnumerable nodes, NodeFactory factory) Out.WriteLine("#include \"CppCodeGen.h\""); Out.WriteLine(); - _statics = new CppGenerationBuffer(); - _statics.Indent(); - _gcStatics = new CppGenerationBuffer(); - _gcStatics.Indent(); - _threadStatics = new CppGenerationBuffer(); - _threadStatics.Indent(); - _gcThreadStatics = new CppGenerationBuffer(); - _gcThreadStatics.Indent(); + _statics = new Dictionary(); + _gcStatics = new Dictionary(); + _threadStatics = new Dictionary(); OutputNodes(nodes, factory); - Out.Write("struct {"); - Out.Write(_statics.ToString()); - Out.Write("} __statics;"); - - Out.Write("struct {"); - Out.Write(_gcStatics.ToString()); - Out.Write("} __gcStatics;"); - - Out.Write("struct {"); - Out.Write(_gcStatics.ToString()); - Out.Write("} __gcThreadStatics;"); - OutputExternCSignatures(); foreach (var node in nodes) diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/EvaluationStack.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/EvaluationStack.cs index feaf2ed2dcd..34ea83ecffe 100644 --- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/EvaluationStack.cs +++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/EvaluationStack.cs @@ -489,6 +489,19 @@ protected override void BuildRepresentation(StringBuilder s) } } + /// + /// Entry representing some ftn token along with its string representation + /// + internal class LdFtnTokenEntry : LdTokenEntry + { + public bool IsVirtual { get; } + + public LdFtnTokenEntry(StackValueKind kind, string name, MethodDesc token, bool isVirtual, TypeDesc type = null) : base(kind, name, token, type) + { + IsVirtual = isVirtual; + } + } + internal class InvalidEntry : StackEntry { /// diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs index 92a7626bcfd..3d8962e649e 100644 --- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs +++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs @@ -35,6 +35,7 @@ internal partial class ILImporter private TypeDesc _thisType; private MethodIL _methodIL; + private MethodIL _canonMethodIL; private byte[] _ilBytes; private LocalVariableDefinition[] _locals; @@ -118,12 +119,25 @@ public ILImporter(Compilation compilation, CppWriter writer, MethodDesc method, if (!_methodSignature.IsStatic) _thisType = method.OwningType; - _methodIL = methodIL; + _canonMethodIL = methodIL; - _ilBytes = _methodIL.GetILBytes(); - _locals = _methodIL.GetLocals(); + // Get the runtime determined method IL so that this works right in shared code + // and tokens in shared code resolve to runtime determined types. + MethodIL uninstantiatiedMethodIL = methodIL.GetMethodILDefinition(); + if (methodIL != uninstantiatiedMethodIL) + { + MethodDesc sharedMethod = method.GetSharedRuntimeFormMethodTarget(); + _methodIL = new InstantiatedMethodIL(sharedMethod, uninstantiatiedMethodIL); + } + else + { + _methodIL = methodIL; + } + + _ilBytes = methodIL.GetILBytes(); + _locals = methodIL.GetLocals(); - var ilExceptionRegions = _methodIL.GetExceptionRegions(); + var ilExceptionRegions = methodIL.GetExceptionRegions(); _exceptionRegions = new ExceptionRegion[ilExceptionRegions.Length]; for (int i = 0; i < ilExceptionRegions.Length; i++) { @@ -185,6 +199,35 @@ public void SetParameterNames(IEnumerable parameters) _parameterIndexToNameMap = parameterIndexToNameMap; } + private ISymbolNode GetGenericLookupHelper(ReadyToRunHelperId helperId, object helperArgument) + { + if (_method.RequiresInstMethodDescArg()) + { + return _nodeFactory.ReadyToRunHelperFromDictionaryLookup(helperId, helperArgument, _method); + } + else + { + Debug.Assert(_method.RequiresInstMethodTableArg() || _method.AcquiresInstMethodTableFromThis()); + return _nodeFactory.ReadyToRunHelperFromTypeLookup(helperId, helperArgument, _method.OwningType); + } + } + + private string GetGenericContext() + { + Debug.Assert(_method.IsSharedByGenericInstantiations); + + if (_method.AcquiresInstMethodTableFromThis()) + { + return String.Concat( + "*(void **)", + GetVarName(0, true)); + } + else + { + return _writer.GetCppHiddenParam(); + } + } + private StackValueKind GetStackValueKind(TypeDesc type) { switch (type.Category) @@ -300,9 +343,19 @@ private void AppendCastIfNecessary(TypeDesc destType, StackEntry srcEntry) ConstantEntry constant = srcEntry as ConstantEntry; if ((constant != null) && (constant.IsCastNecessary(destType)) || !destType.IsValueType || destType != srcEntry.Type) { - Append("("); - Append(GetSignatureTypeNameAndAddReference(destType)); - Append(")"); + if (srcEntry.Kind == StackValueKind.ValueType) + { + Append("*("); + Append(GetSignatureTypeNameAndAddReference(destType)); + Append("*"); + Append(")&"); + } + else + { + Append("("); + Append(GetSignatureTypeNameAndAddReference(destType)); + Append(")"); + } } } @@ -460,6 +513,72 @@ private void AppendComparison(ILOpcode opcode, StackEntry op1, StackEntry op2) } } + private string GetSymbolNodeName(ISymbolNode node) + { + return node.GetMangledName(_nodeFactory.NameMangler).Replace("::", "_"); + } + + private void AppendMethodGenericDictionary(MethodDesc method) + { + ISymbolNode node = _nodeFactory.MethodGenericDictionary(method); + _dependencies.Add(node); + + Append(GetSymbolNodeName(node)); + } + + private void AppendRuntimeMethodHandle(MethodDesc method) + { + ISymbolNode node = _nodeFactory.RuntimeMethodHandle(method); + _dependencies.Add(node); + + Append(_writer.GetCppSymbolNodeName(_nodeFactory, node)); + } + + private void AppendFatFunctionPointer(MethodDesc method, bool isUnboxingStub = false) + { + ISymbolNode node = _nodeFactory.FatFunctionPointer(method, isUnboxingStub); + _dependencies.Add(node); + + Append(_writer.GetCppSymbolNodeName(_nodeFactory, node)); + } + + private string GetGenericLookupHelperAndAddReference(ReadyToRunHelperId helperId, object helperArgument) + { + ISymbolNode node = GetGenericLookupHelper(helperId, helperArgument); + _dependencies.Add(node); + + return _writer.GetCppReadyToRunGenericHelperNodeName(_nodeFactory, node as ReadyToRunGenericHelperNode); + } + + private void AppendStaticFieldGenericLookupHelperAndAddReference(FieldDesc field) + { + Debug.Assert(field.IsStatic); + + ReadyToRunHelperId helperId; + if (field.IsThreadStatic) + { + helperId = ReadyToRunHelperId.GetThreadStaticBase; + } + else if (field.HasGCStaticBase) + { + helperId = ReadyToRunHelperId.GetGCStaticBase; + } + else + { + helperId = ReadyToRunHelperId.GetNonGCStaticBase; + } + + Append(GetGenericLookupHelperAndAddReference(helperId, field.OwningType)); + } + + private void AppendMethodAndAddReference(MethodDesc method, bool isUnboxingStub = false) + { + ISymbolNode node = _nodeFactory.MethodEntrypoint(method, isUnboxingStub); + _dependencies.Add(node); + + Append(GetSymbolNodeName(node)); + } + private StackEntry NewSpillSlot(StackEntry entry) { if (_spillSlots == null) @@ -575,6 +694,8 @@ private string GetVarName(int index, bool argument) private TypeDesc GetVarType(int index, bool argument) { + TypeDesc type; + if (argument) { if (_thisType != null) @@ -582,15 +703,18 @@ private TypeDesc GetVarType(int index, bool argument) if (index == -1) { if (_thisType.IsValueType) - return _thisType.MakeByRefType(); - return _thisType; + type = _thisType.MakeByRefType(); + else + type = _thisType; } - else return _methodSignature[index]; + else type = _methodSignature[index]; } else { - return _locals[index].Type; + type = _locals[index].Type; } + + return _writer.ConvertToCanonFormIfNecessary(type, CanonicalFormKind.Specific); } private TypeDesc GetWellKnownType(WellKnownType wellKnownType) @@ -600,7 +724,7 @@ private TypeDesc GetWellKnownType(WellKnownType wellKnownType) private TypeDesc ResolveTypeToken(int token) { - return (TypeDesc)_methodIL.GetObject(token); + return (TypeDesc)_canonMethodIL.GetObject(token); } private void MarkInstructionBoundary() @@ -636,13 +760,13 @@ public void Compile(CppMethodCodeNode methodCodeNodeNeedingCode) for (int i = 0; i < methodCodeNodeNeedingCode.Method.Signature.Length; i++) { var parameterType = methodCodeNodeNeedingCode.Method.Signature[i]; - AddTypeReference(parameterType, false); + AddTypeReference(_writer.ConvertToCanonFormIfNecessary(parameterType, CanonicalFormKind.Specific), false); } var returnType = methodCodeNodeNeedingCode.Method.Signature.ReturnType; if (!returnType.IsByRef) { - AddTypeReference(returnType, true); + AddTypeReference(_writer.ConvertToCanonFormIfNecessary(returnType, CanonicalFormKind.Specific), true); } var owningType = methodCodeNodeNeedingCode.Method.OwningType; @@ -682,14 +806,15 @@ public void Compile(CppMethodCodeNode methodCodeNodeNeedingCode) bool initLocals = _methodIL.IsInitLocals; for (int i = 0; i < _locals.Length; i++) { + TypeDesc localType = _writer.ConvertToCanonFormIfNecessary(_locals[i].Type, CanonicalFormKind.Specific); + AppendLine(); - Append(GetSignatureTypeNameAndAddReference(_locals[i].Type)); + Append(GetSignatureTypeNameAndAddReference(localType)); Append(" "); Append(GetVarName(i, false)); if (initLocals) { - TypeDesc localType = _locals[i].Type; if (localType.IsValueType && !localType.IsPrimitive && !localType.IsEnum) { AppendSemicolon(); @@ -882,19 +1007,32 @@ private void ImportJmp(int token) private void ImportCasting(ILOpcode opcode, int token) { - TypeDesc type = (TypeDesc)_methodIL.GetObject(token); + TypeDesc runtimeDeterminedType = (TypeDesc)_methodIL.GetObject(token); + TypeDesc type = (TypeDesc)_canonMethodIL.GetObject(token); + TypeDesc canonType = _writer.ConvertToCanonFormIfNecessary(type, CanonicalFormKind.Specific); var value = _stack.Pop(); - PushTemp(StackValueKind.ObjRef, type); + PushTemp(StackValueKind.ObjRef, canonType); - AddTypeReference(type, false); + AddTypeReference(canonType, false); Append(opcode == ILOpcode.isinst ? "__isinst" : "__castclass"); Append("("); Append(value); Append(", "); - Append(_writer.GetCppTypeName(type)); - Append("::__getMethodTable())"); + if (runtimeDeterminedType.IsRuntimeDeterminedSubtype) + { + Append("(MethodTable *)"); + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeDeterminedType)); + Append("("); + Append(GetGenericContext()); + Append("))"); + } + else + { + Append(_writer.GetCppTypeName(runtimeDeterminedType)); + Append("::__getMethodTable())"); + } AppendSemicolon(); } @@ -973,7 +1111,21 @@ private bool ImportIntrinsicCall(MethodDesc method) { var typeHandleSlot = (LdTokenEntry)_stack.Pop(); TypeDesc typeOfEEType = typeHandleSlot.LdToken; - PushExpression(StackValueKind.NativeInt, string.Concat("((intptr_t)", _writer.GetCppTypeName(typeOfEEType), "::__getMethodTable())")); + + string expr; + + if (typeOfEEType.IsRuntimeDeterminedSubtype) + { + expr = string.Concat( + "(intptr_t)", + GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, typeOfEEType), + "(", GetGenericContext(), ")"); + } + else + { + expr = string.Concat("((intptr_t)", _writer.GetCppTypeName(typeOfEEType), "::__getMethodTable())"); + } + PushExpression(StackValueKind.NativeInt, expr); return true; } break; @@ -1015,13 +1167,15 @@ private bool ImportIntrinsicCall(MethodDesc method) return false; } - private void ImportNewObjArray(TypeDesc owningType, MethodDesc method) + private void ImportNewObjArray(TypeDesc owningType, MethodDesc runtimeMethod) { AppendLine(); + TypeDesc canonOwningType = _writer.ConvertToCanonFormIfNecessary(owningType, CanonicalFormKind.Specific); + string dimensionsTemp = NewTempName(); Append("int32_t " + dimensionsTemp + "[] = { "); - int argumentsCount = method.Signature.Length; + int argumentsCount = runtimeMethod.Signature.Length; for (int i = 0; i < argumentsCount; i++) { Append("(int32_t)("); @@ -1032,17 +1186,30 @@ private void ImportNewObjArray(TypeDesc owningType, MethodDesc method) Append("};"); - PushTemp(StackValueKind.ObjRef, owningType); + PushTemp(StackValueKind.ObjRef, canonOwningType); - AddTypeReference(owningType, true); + AddTypeReference(canonOwningType, true); MethodDesc helper = _typeSystemContext.GetHelperEntryPoint("ArrayHelpers", "NewObjArray"); AddMethodReference(helper); Append(_writer.GetCppTypeName(helper.OwningType) + "::" + _writer.GetCppMethodName(helper)); Append("((intptr_t)"); - Append(_writer.GetCppTypeName(method.OwningType)); - Append("::__getMethodTable(),"); + + if (!runtimeMethod.OwningType.IsRuntimeDeterminedSubtype) + { + Append(_writer.GetCppTypeName(runtimeMethod.OwningType)); + Append("::__getMethodTable(),"); + } + else + { + Append("(MethodTable *)"); + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeMethod.OwningType)); + Append("("); + Append(GetGenericContext()); + Append("),"); + } + Append(argumentsCount.ToStringInvariant()); Append(","); Append(dimensionsTemp); @@ -1055,9 +1222,11 @@ private void ImportCall(ILOpcode opcode, int token) bool callViaSlot = false; bool delegateInvoke = false; bool callViaInterfaceDispatch = false; + bool callViaGVMDispatch = false; DelegateCreationInfo delegateInfo = null; - MethodDesc method = (MethodDesc)_methodIL.GetObject(token); + var runtimeDeterminedMethod = (MethodDesc)_methodIL.GetObject(token); + var method = (MethodDesc)_canonMethodIL.GetObject(token); if (method.IsIntrinsic) { @@ -1077,12 +1246,16 @@ private void ImportCall(ILOpcode opcode, int token) } TypeDesc constrained = null; + bool resolvedConstraint = false; if (opcode != ILOpcode.newobj) { if ((_pendingPrefix & Prefix.Constrained) != 0 && opcode == ILOpcode.callvirt) { _pendingPrefix &= ~Prefix.Constrained; constrained = _constrained; + if (constrained.IsRuntimeDeterminedSubtype) + constrained = constrained.ConvertToCanonForm(CanonicalFormKind.Specific); + bool forceUseRuntimeLookup; var constrainedType = constrained.GetClosestDefType(); MethodDesc directMethod = constrainedType.TryResolveConstraintMethodApprox(method.OwningType, method, out forceUseRuntimeLookup); @@ -1094,9 +1267,10 @@ private void ImportCall(ILOpcode opcode, int token) { method = directMethod; opcode = ILOpcode.call; + resolvedConstraint = true; } - //If constrainedType is a value type and constrainedType does not implement method (directMethod == null) then ptr is - //dereferenced, boxed, and passed as the 'this' pointer to the callvirt method instruction. + //If constrainedType is a value type and constrainedType does not implement method (directMethod == null) then ptr is + //dereferenced, boxed, and passed as the 'this' pointer to the callvirt method instruction. else if (constrainedType.IsValueType) { int thisPosition = _stack.Top - (method.Signature.Length + 1); @@ -1112,11 +1286,15 @@ private void ImportCall(ILOpcode opcode, int token) TypeDesc owningType = method.OwningType; TypeDesc retType = null; + TypeDesc runtimeDeterminedRetType = null; + + string delegateCtorHelper = null; { if (opcode == ILOpcode.newobj) { retType = owningType; + runtimeDeterminedRetType = runtimeDeterminedMethod.OwningType; if (owningType.IsString) { @@ -1128,13 +1306,20 @@ private void ImportCall(ILOpcode opcode, int token) } else if (owningType.IsArray) { - ImportNewObjArray(owningType, method); + ImportNewObjArray(owningType, runtimeDeterminedMethod); return; } else if (owningType.IsDelegate) { - delegateInfo = _compilation.GetDelegateCtor(owningType, ((LdTokenEntry)_stack.Peek()).LdToken, followVirtualDispatch: false); + TypeDesc canonDelegateType = owningType.ConvertToCanonForm(CanonicalFormKind.Specific); + LdFtnTokenEntry ldFtnTokenEntry = (LdFtnTokenEntry)_stack.Peek(); + delegateInfo = _compilation.GetDelegateCtor(canonDelegateType, ldFtnTokenEntry.LdToken, followVirtualDispatch: false); method = delegateInfo.Constructor.Method; + + if (delegateInfo.NeedsRuntimeLookup && !ldFtnTokenEntry.IsVirtual) + { + delegateCtorHelper = GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.DelegateCtor, delegateInfo); + } } } else @@ -1148,6 +1333,16 @@ private void ImportCall(ILOpcode opcode, int token) } } + bool exactContextNeedsRuntimeLookup; + if (method.HasInstantiation) + { + exactContextNeedsRuntimeLookup = method.IsSharedByGenericInstantiations; + } + else + { + exactContextNeedsRuntimeLookup = method.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any); + } + if (opcode == ILOpcode.callvirt) { // TODO: Null checks @@ -1158,37 +1353,48 @@ private void ImportCall(ILOpcode opcode, int token) if (!method.IsNewSlot) throw new NotImplementedException(); - if (method.OwningType.IsInterface) + if (method.HasInstantiation) + callViaGVMDispatch = true; + else if (method.OwningType.IsInterface) callViaInterfaceDispatch = true; else callViaSlot = true; - if (!_nodeFactory.VTable(method.OwningType).HasFixedSlots) + if (!callViaGVMDispatch && !_nodeFactory.VTable(method.OwningType).HasFixedSlots) _dependencies.Add(_nodeFactory.VirtualMethodUse(method)); + else if (callViaGVMDispatch) + _dependencies.Add(_nodeFactory.GVMDependencies(method)); } } - if (!callViaSlot && !delegateInvoke && !callViaInterfaceDispatch) - AddMethodReference(method); + var canonMethod = method.GetCanonMethodTarget(CanonicalFormKind.Specific); - if (opcode == ILOpcode.newobj) - AddTypeReference(retType, true); + if (!callViaSlot && !delegateInvoke && !callViaInterfaceDispatch && !callViaGVMDispatch) + AddMethodReference(canonMethod); - var methodSignature = method.Signature; + var canonMethodSignature = canonMethod.Signature; if (retType == null) - retType = methodSignature.ReturnType; + retType = method.Signature.ReturnType; + + retType = _writer.ConvertToCanonFormIfNecessary(retType, CanonicalFormKind.Specific); + + if (opcode == ILOpcode.newobj) + AddTypeReference(retType, true); string temp = null; StackValueKind retKind = StackValueKind.Unknown; var needNewLine = false; + string gvmSlotVarName = null; if (callViaInterfaceDispatch) { - ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (methodSignature.Length + 1)]; + ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (canonMethodSignature.Length + 1)]; - string typeDefName = _writer.GetCppMethodName(method); - _writer.AppendSignatureTypeDef(_builder, typeDefName, method.Signature, method.OwningType); + string typeDefName = _writer.GetCppTypeName(canonMethod.OwningType) + "_" + _writer.GetCppMethodName(canonMethod); + typeDefName = typeDefName.Replace("::", "_"); + _writer.AppendSignatureTypeDef(_builder, typeDefName, canonMethodSignature, + canonMethod.OwningType, canonMethod.RequiresInstMethodDescArg()); string functionPtr = NewTempName(); AppendEmptyLine(); @@ -1196,40 +1402,146 @@ private void ImportCall(ILOpcode opcode, int token) Append("void*"); Append(functionPtr); Append(" = (void*) "); - GetFunctionPointerForInterfaceMethod(method, v, typeDefName); + GetFunctionPointerForInterfaceMethod(runtimeDeterminedMethod, v, typeDefName); PushExpression(StackValueKind.ByRef, functionPtr); } + else if (callViaGVMDispatch) + { + ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (canonMethodSignature.Length + 1)]; + + MethodDesc helper = _typeSystemContext.SystemModule.GetKnownType("System.Runtime", "TypeLoaderExports").GetKnownMethod("GVMLookupForSlot", null); + AddMethodReference(helper); + + gvmSlotVarName = NewTempName(); + AppendEmptyLine(); + + Append("intptr_t "); + Append(gvmSlotVarName); + Append(" = "); + Append(_writer.GetCppTypeName(helper.OwningType) + "::" + _writer.GetCppMethodName(helper)); + Append("("); + Append("(::System_Private_CoreLib::System::Object*)"); + Append(v.Name); + Append(", "); + + if (exactContextNeedsRuntimeLookup) + { + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.MethodHandle, runtimeDeterminedMethod)); + Append("("); + Append(GetGenericContext()); + Append(")"); + } + else + { + AppendRuntimeMethodHandle(runtimeDeterminedMethod); + Append("()"); + } + Append(");"); + + string functionPtr = NewTempName(); + + Append("intptr_t "); + Append(functionPtr); + AppendSemicolon(); + + Append("if ("); + Append(gvmSlotVarName); + Append(" & 0x2) {"); + Append(functionPtr); + Append(" = *(intptr_t*)("); + Append(gvmSlotVarName); + Append(" - 0x2);} else {"); + Append(functionPtr); + Append(" = "); + Append(gvmSlotVarName); + Append(";};"); + + PushExpression(StackValueKind.ValueType, functionPtr); + } + + string arrayAddressMethodHiddenArg = null; + + if (canonMethod.IsArrayAddressMethod()) + { + arrayAddressMethodHiddenArg = NewTempName(); + + Append("::System_Private_CoreLib::System::EETypePtr "); + Append(arrayAddressMethodHiddenArg); + Append(" = {(::System_Private_CoreLib::Internal::Runtime::EEType*)"); + + TypeDesc type; + + if (!resolvedConstraint) + type = runtimeDeterminedMethod.OwningType; + else + type = _constrained; + + if (exactContextNeedsRuntimeLookup) + { + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, type)); + + Append("("); + Append(GetGenericContext()); + Append(")"); + } + else + { + Append(_writer.GetCppTypeName(type)); + Append("::__getMethodTable()"); + + AddTypeReference(type, true); + } + + Append("};"); + } + + TypeDesc canonRetType = null; if (!retType.IsVoid) { - retKind = GetStackValueKind(retType); + if (opcode == ILOpcode.newobj) + { + canonRetType = retType; + } + else + { + canonRetType = _writer.ConvertToCanonFormIfNecessary(canonMethodSignature.ReturnType, CanonicalFormKind.Specific); + } + + retKind = GetStackValueKind(canonRetType); temp = NewTempName(); AppendLine(); - Append(GetStackValueKindCPPTypeName(retKind, retType)); + Append(GetStackValueKindCPPTypeName(retKind, canonRetType)); Append(" "); Append(temp); - if (retType.IsValueType && opcode == ILOpcode.newobj) + if (canonRetType.IsValueType && opcode == ILOpcode.newobj || callViaGVMDispatch) { - Append(";"); - needNewLine = true; + AppendSemicolon(); + + if (!callViaGVMDispatch) + needNewLine = true; } else { Append(" = "); - if (retType.IsPointer) + if (canonRetType.IsPointer) { Append("(intptr_t)"); } + else + { + AppendCastIfNecessary(retKind, canonRetType); + } } } else { needNewLine = true; } - AddTypeReference(method.OwningType, true); + AddTypeReference(canonMethod.OwningType, true); if (opcode == ILOpcode.newobj) { @@ -1239,8 +1551,23 @@ private void ImportCall(ILOpcode opcode, int token) if (needNewLine) AppendLine(); Append("__allocate_object("); - Append(_writer.GetCppTypeName(retType)); - Append("::__getMethodTable())"); + + if (runtimeDeterminedRetType.IsRuntimeDeterminedSubtype) + { + Append("(MethodTable *)"); + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeDeterminedRetType)); + Append("("); + Append(GetGenericContext()); + Append("))"); + } + else + { + Append(_writer.GetCppTypeName(runtimeDeterminedRetType)); + Append("::__getMethodTable())"); + + AddTypeReference(runtimeDeterminedRetType, true); + } + AppendSemicolon(); needNewLine = true; @@ -1269,12 +1596,13 @@ private void ImportCall(ILOpcode opcode, int token) if (callViaSlot || delegateInvoke) { - ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (methodSignature.Length + 1)]; + ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (canonMethodSignature.Length + 1)]; + Append("(*"); - Append(_writer.GetCppTypeName(method.OwningType)); + Append(_writer.GetCppTypeName(canonMethod.OwningType)); Append("::"); Append(delegateInvoke ? "__invoke__" : "__getslot__"); - Append(_writer.GetCppMethodName(method)); + Append(_writer.GetCppMethodName(canonMethod)); Append("("); Append(v); Append("))"); @@ -1289,54 +1617,264 @@ private void ImportCall(ILOpcode opcode, int token) else if (callViaInterfaceDispatch) { Append("(("); - Append(_writer.GetCppMethodName(method)); + Append(_writer.GetCppTypeName(canonMethod.OwningType).Replace("::", "_")); + Append("_"); + Append(_writer.GetCppMethodName(canonMethod)); Append(")"); ExpressionEntry v = (ExpressionEntry)_stack.Pop(); Append(v); Append(")"); } - else + else if (delegateCtorHelper != null) { - Append(_writer.GetCppTypeName(method.OwningType)); + Append(delegateCtorHelper); + } + else if (!callViaGVMDispatch) + { + Append(_writer.GetCppTypeName(canonMethod.OwningType)); Append("::"); - Append(_writer.GetCppMethodName(method)); + Append(_writer.GetCppMethodName(canonMethod)); } TypeDesc thisArgument = null; - Append("("); - if (opcode == ILOpcode.newobj) + if (opcode != ILOpcode.newobj && !canonMethodSignature.IsStatic) { - Append("("); - if (retType.IsValueType) + thisArgument = canonMethod.OwningType; + if (thisArgument.IsValueType) + thisArgument = thisArgument.MakeByRefType(); + } + + if (callViaGVMDispatch) + { + string typeDefName = _writer.GetCppTypeName(canonMethod.OwningType) + "_" + _writer.GetCppMethodName(canonMethod); + typeDefName = typeDefName.Replace("::", "_"); + + ExpressionEntry v = (ExpressionEntry)_stack.Pop(); + + Append("if ("); + Append(gvmSlotVarName); + Append(" & 0x2) {"); + + _writer.AppendSignatureTypeDef(_builder, typeDefName, canonMethodSignature, + canonMethod.OwningType, true); + + if (canonRetType != null && !canonRetType.IsValueType) { - Append(_writer.GetCppSignatureTypeName(retType.MakeByRefType())); - Append(")"); - Append("&" + temp); + Append(temp); + Append(" = "); + + if (canonRetType.IsPointer) + { + Append("(intptr_t)"); + } + else + { + AppendCastIfNecessary(GetStackValueKind(canonRetType), canonRetType); + } } - else + + Append("(("); + Append(_writer.GetCppTypeName(canonMethod.OwningType).Replace("::", "_")); + Append("_"); + Append(_writer.GetCppMethodName(canonMethod)); + Append(")"); + Append(v); + Append(")("); + + PassThisArgumentIfNeeded(canonMethodSignature, thisArgument); + + if (thisArgument != null) + Append(", "); + + Append("**(void***)("); + Append(gvmSlotVarName); + Append("- 0x2 + sizeof(void*))"); + + if (canonMethodSignature.Length > 0) + Append(", "); + + PassCallArguments(canonMethodSignature, thisArgument, false); + + Append(");} else {"); + + _writer.AppendSignatureTypeDef(_builder, typeDefName, canonMethodSignature, + canonMethod.OwningType, false); + + if (canonRetType != null && !canonRetType.IsValueType) { - Append(_writer.GetCppSignatureTypeName(retType)); - Append(")"); Append(temp); + Append(" = "); + + if (canonRetType.IsPointer) + { + Append("(intptr_t)"); + } + else + { + AppendCastIfNecessary(GetStackValueKind(canonRetType), canonRetType); + } } - if (methodSignature.Length > 0) + + Append("(("); + Append(_writer.GetCppTypeName(canonMethod.OwningType).Replace("::", "_")); + Append("_"); + Append(_writer.GetCppMethodName(canonMethod)); + Append(")"); + Append(v); + Append(")("); + + PassThisArgumentIfNeeded(canonMethodSignature, thisArgument); + + if (thisArgument != null && canonMethodSignature.Length > 0) Append(", "); + + PassCallArguments(canonMethodSignature, thisArgument); + + Append(");};"); } else { - if (!methodSignature.IsStatic) + Append("("); + + if (opcode == ILOpcode.newobj) { - thisArgument = owningType; - if (thisArgument.IsValueType) - thisArgument = thisArgument.MakeByRefType(); + if (delegateCtorHelper != null) + { + Append(GetGenericContext()); + Append(", "); + } + + canonRetType = _writer.ConvertToCanonFormIfNecessary(canonMethod.OwningType, CanonicalFormKind.Specific); + + Append("("); + if (canonRetType.IsValueType) + { + Append(_writer.GetCppSignatureTypeName(canonRetType.MakeByRefType())); + Append(")"); + Append("&" + temp); + } + else + { + Append(_writer.GetCppSignatureTypeName(canonRetType)); + Append(")"); + Append(temp); + } + if (canonMethodSignature.Length > 0) + Append(", "); } + + PassThisArgumentIfNeeded(canonMethodSignature, thisArgument); + + if (thisArgument != null && + (canonMethod.IsArrayAddressMethod() || canonMethod.RequiresInstArg() || canonMethodSignature.Length > 0)) + Append(", "); + + if (canonMethod.IsArrayAddressMethod()) + { + Append(arrayAddressMethodHiddenArg); + + if (canonMethodSignature.Length > 0) + Append(", "); + } + else if (canonMethod.RequiresInstArg()) + { + if (exactContextNeedsRuntimeLookup) + { + if (!resolvedConstraint) + { + if (canonMethod.RequiresInstMethodDescArg()) + { + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.MethodDictionary, runtimeDeterminedMethod)); + } + else + { + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeDeterminedMethod.OwningType)); + } + + Append("("); + Append(GetGenericContext()); + Append(")"); + } + else + { + Debug.Assert(canonMethod.RequiresInstMethodTableArg()); + + if (canonMethod.RequiresInstMethodTableArg()) + { + if (_constrained.IsRuntimeDeterminedSubtype) + { + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, _constrained)); + + Append("("); + Append(GetGenericContext()); + Append(")"); + } + else + { + Append(_writer.GetCppTypeName(_constrained)); + Append("::__getMethodTable()"); + + AddTypeReference(_constrained, true); + } + } + } + } + else + { + if (canonMethod.RequiresInstMethodDescArg()) + { + Append("&"); + AppendMethodGenericDictionary(method); + } + else + { + Append(_writer.GetCppTypeName(method.OwningType)); + Append("::__getMethodTable()"); + + AddTypeReference(method.OwningType, true); + } + } + + if (canonMethodSignature.Length > 0) + Append(", "); + } + + PassCallArguments(canonMethodSignature, thisArgument); + Append(")"); } - PassCallArguments(methodSignature, thisArgument); - Append(")"); if (temp != null) { Debug.Assert(retKind != StackValueKind.Unknown, "Valid return type"); + + if (opcode != ILOpcode.newobj && + retType != _writer.ConvertToCanonFormIfNecessary(canonMethodSignature.ReturnType, CanonicalFormKind.Specific)) + { + string retVar = temp; + retKind = GetStackValueKind(retType); + temp = NewTempName(); + + AppendSemicolon(); + Append(GetStackValueKindCPPTypeName(retKind, retType)); + Append(" "); + Append(temp); + Append(" = "); + + if (retType.IsValueType && !retType.IsPrimitive) + { + Append("*("); + Append(_writer.GetCppSignatureTypeName(retType)); + Append("*)&"); + } + else + { + Append("("); + Append(_writer.GetCppSignatureTypeName(retType)); + Append(")"); + } + Append(retVar); + } + PushExpression(retKind, temp, retType); } AppendSemicolon(); @@ -1388,54 +1926,76 @@ private void GetFunctionPointerForInterfaceMethod(MethodDesc method, ExpressionE // Get EEType of interface Append("((::System_Private_CoreLib::Internal::Runtime::EEType *)("); - Append(_writer.GetCppTypeName(method.OwningType)); - Append("::__getMethodTable()))"); + + if (method.OwningType.IsRuntimeDeterminedSubtype) + { + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, method.OwningType)); + Append("("); + Append(GetGenericContext()); + Append(")))"); + } + else + { + Append(_writer.GetCppTypeName(method.OwningType)); + Append("::__getMethodTable()))"); + } Append(", "); + MethodDesc canonMethod = method.GetCanonMethodTarget(CanonicalFormKind.Specific); + // Get slot of implementation Append("(uint16_t)"); Append("("); - Append(_writer.GetCppTypeName(method.OwningType)); + Append(_writer.GetCppTypeName(canonMethod.OwningType)); Append("::"); Append("__getslot__"); - Append(_writer.GetCppMethodName(method)); + Append(_writer.GetCppMethodName(canonMethod)); Append("("); Append(v.Name); Append("))"); - Append("));"); + Append("));"); + } + + private void PassThisArgumentIfNeeded(MethodSignature methodSignature, TypeDesc thisArgument) + { + if (thisArgument == null) + return; + + int signatureLength = methodSignature.Length; + int argumentsCount = (thisArgument != null) ? (signatureLength + 1) : signatureLength; + int thisIndex = _stack.Top - argumentsCount; + + var op = _stack[thisIndex]; + AppendCastIfNecessary(_writer.ConvertToCanonFormIfNecessary(thisArgument, CanonicalFormKind.Specific), op); + Append(op); } - private void PassCallArguments(MethodSignature methodSignature, TypeDesc thisArgument) + private void PassCallArguments(MethodSignature methodSignature, TypeDesc thisArgument, bool clearStack = true) { int signatureLength = methodSignature.Length; int argumentsCount = (thisArgument != null) ? (signatureLength + 1) : signatureLength; - int startingIndex = _stack.Top - argumentsCount; - for (int i = 0; i < argumentsCount; i++) + int startingIndex = _stack.Top - signatureLength; + + for (int i = 0; i < signatureLength; i++) { var op = _stack[startingIndex + i]; - int argIndex = signatureLength - (argumentsCount - i); - TypeDesc argType; - if (argIndex == -1) - { - argType = thisArgument; - } - else - { - argType = methodSignature[argIndex]; - } - AppendCastIfNecessary(argType, op); + + AppendCastIfNecessary(_writer.ConvertToCanonFormIfNecessary(methodSignature[i], CanonicalFormKind.Specific), op); Append(op); - if (i + 1 != argumentsCount) + + if (i != signatureLength - 1) Append(", "); } - _stack.PopN(argumentsCount); + + if (clearStack) + _stack.PopN(argumentsCount); } private void ImportCalli(int token) { - MethodSignature methodSignature = (MethodSignature)_methodIL.GetObject(token); + MethodSignature methodSignature = (MethodSignature)_canonMethodIL.GetObject(token); TypeDesc thisArgument = null; if (!methodSignature.IsStatic) @@ -1445,9 +2005,6 @@ private void ImportCalli(int token) thisArgument = thisArgument.MakeByRefType(); } - string typeDefName = "__calli__" + token.ToStringInvariant("x8"); - _writer.AppendSignatureTypeDef(_builder, typeDefName, methodSignature, thisArgument); - TypeDesc retType = methodSignature.ReturnType; StackValueKind retKind = StackValueKind.Unknown; @@ -1461,6 +2018,40 @@ private void ImportCalli(int token) AppendLine(); Append(GetStackValueKindCPPTypeName(retKind, retType)); Append(" "); + Append(temp); + AppendSemicolon(); + } + else + { + AppendLine(); + } + + var fnPtrValue = _stack.Pop(); + + string fatPtr = NewTempName(); + + Append("intptr_t "); + Append(fatPtr); + Append(" = "); + Append(fnPtrValue); + + AppendSemicolon(); + + Append("if ("); + Append(fatPtr); + Append(" & 0x2) {"); + Append(fnPtrValue); + Append(" = *(intptr_t*)("); + Append(fatPtr); + Append(" - 0x2)"); + + AppendSemicolon(); + + string typeDefName = "__calli__" + token.ToStringInvariant("x8"); + _writer.AppendSignatureTypeDef(_builder, typeDefName, methodSignature, thisArgument, true); + + if (!retType.IsVoid) + { Append(temp); Append(" = "); @@ -1469,74 +2060,183 @@ private void ImportCalli(int token) Append("(intptr_t)"); } } - else + + Append("(("); + Append(typeDefName); + Append(")"); + Append(fnPtrValue); + Append(")("); + + PassThisArgumentIfNeeded(methodSignature, thisArgument); + + if (thisArgument != null) + Append(", "); + + Append("**(void***)("); + Append(fatPtr); + Append(" - 0x2 + sizeof(void*))"); + + if (methodSignature.Length > 0) + Append(", "); + + PassCallArguments(methodSignature, thisArgument, false); + Append(")"); + + AppendSemicolon(); + + Append("} else {"); + + _writer.AppendSignatureTypeDef(_builder, typeDefName, methodSignature, thisArgument, false); + + if (!retType.IsVoid) { - AppendLine(); + Append(temp); + Append(" = "); + + if (retType.IsPointer) + { + Append("(intptr_t)"); + } } - var fnPtrValue = _stack.Pop(); Append("(("); Append(typeDefName); Append(")"); Append(fnPtrValue); Append(")("); + PassThisArgumentIfNeeded(methodSignature, thisArgument); + + if (thisArgument != null && methodSignature.Length > 0) + Append(", "); + PassCallArguments(methodSignature, thisArgument); Append(")"); + AppendSemicolon(); + Append("}"); + + AppendSemicolon(); + if (temp != null) { Debug.Assert(retKind != StackValueKind.Unknown, "Valid return type"); PushExpression(retKind, temp, retType); } - - AppendSemicolon(); } private void ImportLdFtn(int token, ILOpcode opCode) { - MethodDesc method = (MethodDesc)_methodIL.GetObject(token); + MethodDesc runtimeDeterminedMethod = (MethodDesc)_methodIL.GetObject(token); + MethodDesc method = ((MethodDesc)_canonMethodIL.GetObject(token)); + MethodDesc canonMethod = method.GetCanonMethodTarget(CanonicalFormKind.Specific); - if (opCode == ILOpcode.ldvirtftn && method.IsVirtual && method.OwningType.IsInterface) + if (opCode == ILOpcode.ldvirtftn && canonMethod.IsVirtual && !canonMethod.HasInstantiation && canonMethod.OwningType.IsInterface) { - AddVirtualMethodReference(method); - var entry = new LdTokenEntry(StackValueKind.NativeInt, NewTempName(), method); + AddVirtualMethodReference(canonMethod); + var entry = new LdFtnTokenEntry(StackValueKind.NativeInt, NewTempName(), runtimeDeterminedMethod, true); ExpressionEntry v = (ExpressionEntry)_stack.Pop(); - string typeDefName = _writer.GetCppMethodName(method); - _writer.AppendSignatureTypeDef(_builder, typeDefName, method.Signature, method.OwningType); + string typeDefName = _writer.GetCppTypeName(canonMethod.OwningType) + "_" + _writer.GetCppMethodName(canonMethod); + typeDefName = typeDefName.Replace("::", "_"); + _writer.AppendSignatureTypeDef(_builder, typeDefName, canonMethod.Signature, canonMethod.OwningType); AppendEmptyLine(); PushTemp(entry); Append("(intptr_t) "); - GetFunctionPointerForInterfaceMethod(method, v, typeDefName); + GetFunctionPointerForInterfaceMethod(runtimeDeterminedMethod, v, typeDefName); } else { - AddMethodReference(method); - var entry = new LdTokenEntry(StackValueKind.NativeInt, NewTempName(), method); - - if (opCode == ILOpcode.ldvirtftn && method.IsVirtual) + bool isVirtual = opCode == ILOpcode.ldvirtftn && canonMethod.IsVirtual; + var entry = new LdFtnTokenEntry(StackValueKind.NativeInt, NewTempName(), runtimeDeterminedMethod, isVirtual); + + if (isVirtual) { //ldvirtftn requires an object instance, we have to pop one off the stack //then call the associated getslot method passing in the object instance to get the real function pointer ExpressionEntry v = (ExpressionEntry)_stack.Pop(); + PushTemp(entry); Append("(intptr_t)"); - Append(_writer.GetCppTypeName(method.OwningType)); - Append("::__getslot__"); - Append(_writer.GetCppMethodName(method)); - Append("("); - Append(v.Name); - Append(")"); + + if (!canonMethod.HasInstantiation) + { + Append(_writer.GetCppTypeName(canonMethod.OwningType)); + Append("::__getslot__"); + Append(_writer.GetCppMethodName(canonMethod)); + Append("("); + Append(v.Name); + Append(")"); + } + else + { + MethodDesc helper = _typeSystemContext.SystemModule.GetKnownType("System.Runtime", "TypeLoaderExports").GetKnownMethod("GVMLookupForSlot", null); + AddMethodReference(helper); + + Append(_writer.GetCppTypeName(helper.OwningType) + "::" + _writer.GetCppMethodName(helper)); + Append("("); + Append("(::System_Private_CoreLib::System::Object*)"); + Append(v.Name); + Append(", "); + + if (method.IsSharedByGenericInstantiations) + { + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.MethodHandle, runtimeDeterminedMethod)); + Append("("); + Append(GetGenericContext()); + Append(")"); + } + else + { + AppendRuntimeMethodHandle(runtimeDeterminedMethod); + Append("()"); + } + Append(")"); + } AppendSemicolon(); + + if (!canonMethod.HasInstantiation && !_nodeFactory.VTable(canonMethod.OwningType).HasFixedSlots) + _dependencies.Add(_nodeFactory.VirtualMethodUse(canonMethod)); + else if (canonMethod.HasInstantiation) + _dependencies.Add(_nodeFactory.GVMDependencies(canonMethod)); } else { + bool exactContextNeedsRuntimeLookup; + if (method.HasInstantiation) + { + exactContextNeedsRuntimeLookup = method.IsSharedByGenericInstantiations; + } + else + { + exactContextNeedsRuntimeLookup = method.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any); + } + PushTemp(entry); - Append("(intptr_t)&"); - Append(_writer.GetCppTypeName(method.OwningType)); - Append("::"); - Append(_writer.GetCppMethodName(method)); + + bool needUnbox = canonMethod.OwningType.IsValueType && !canonMethod.Signature.IsStatic; + + if (canonMethod.IsSharedByGenericInstantiations && (canonMethod.HasInstantiation || canonMethod.Signature.IsStatic)) + { + if (exactContextNeedsRuntimeLookup) + { + // Actual address will be obtained in runtime helper + Append("0"); + } + else + { + Append("((intptr_t)"); + AppendFatFunctionPointer(runtimeDeterminedMethod, needUnbox); + Append("()) + 0x2"); + } + } + else + { + Append("(intptr_t)&"); + Append(_writer.GetCppTypeName(canonMethod.OwningType)); + Append("::"); + AppendMethodAndAddReference(canonMethod, needUnbox); + } AppendSemicolon(); } @@ -1863,51 +2563,69 @@ private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool private void ImportLoadField(int token, bool isStatic) { - FieldDesc field = (FieldDesc)_methodIL.GetObject(token); - - AddFieldReference(field); + FieldDesc runtimeDeterminedField = (FieldDesc)_methodIL.GetObject(token); + FieldDesc field = (FieldDesc)_canonMethodIL.GetObject(token); var thisPtr = isStatic ? InvalidEntry.Entry : _stack.Pop(); - TypeDesc owningType = field.OwningType; - TypeDesc fieldType = field.FieldType; + TypeDesc runtimeDeterminedOwningType = runtimeDeterminedField.OwningType; + + TypeDesc owningType = _writer.ConvertToCanonFormIfNecessary(field.OwningType, CanonicalFormKind.Specific); + TypeDesc fieldType = _writer.ConvertToCanonFormIfNecessary(field.FieldType, CanonicalFormKind.Specific); // TODO: Is this valid combination? if (!isStatic && !owningType.IsValueType && thisPtr.Kind != StackValueKind.ObjRef) throw new InvalidProgramException(); - if (field.IsStatic) - TriggerCctor(field.OwningType); + if (!runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic) + TriggerCctor(runtimeDeterminedField.OwningType); StackValueKind kind = GetStackValueKind(fieldType); PushTemp(kind, fieldType); AppendCastIfNecessary(kind, fieldType); - if (field.IsStatic) + if (runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic) { - if (!fieldType.IsValueType) - Append("__gcStatics."); - else - Append("__statics."); - Append(_writer.GetCppStaticFieldName(field)); - } - else - if (thisPtr.Kind == StackValueKind.ValueType) - { - Append(thisPtr); - Append("."); + AddTypeReference(fieldType, false); + + Append("((("); + Append(_writer.GetCppStaticsTypeName(owningType, field.HasGCStaticBase, field.IsThreadStatic)); + Append("*)"); + AppendStaticFieldGenericLookupHelperAndAddReference(runtimeDeterminedField); + Append("("); + Append(GetGenericContext()); + Append("))->"); Append(_writer.GetCppFieldName(field)); + Append(")"); } else { - Append("(("); - Append(_writer.GetCppTypeName(owningType)); - Append("*)"); - Append(thisPtr); - Append(")->"); - Append(_writer.GetCppFieldName(field)); + AddFieldReference(field); + + if (field.IsStatic) + { + Append(_writer.GetCppStaticsName(owningType, field.HasGCStaticBase, field.IsThreadStatic)); + Append("."); + Append(_writer.GetCppFieldName(field)); + } + else + if (thisPtr.Kind == StackValueKind.ValueType) + { + Append(thisPtr); + Append("."); + Append(_writer.GetCppFieldName(field)); + } + else + { + Append("(("); + Append(_writer.GetCppTypeName(owningType)); + Append("*)"); + Append(thisPtr); + Append(")->"); + Append(_writer.GetCppFieldName(field)); - GetSignatureTypeNameAndAddReference(owningType); + GetSignatureTypeNameAndAddReference(owningType); + } } AppendSemicolon(); @@ -1915,52 +2633,75 @@ private void ImportLoadField(int token, bool isStatic) private void ImportAddressOfField(int token, bool isStatic) { - FieldDesc field = (FieldDesc)_methodIL.GetObject(token); - - AddFieldReference(field); + FieldDesc runtimeDeterminedField = (FieldDesc)_methodIL.GetObject(token); + FieldDesc field = (FieldDesc)_canonMethodIL.GetObject(token); var thisPtr = isStatic ? InvalidEntry.Entry : _stack.Pop(); - TypeDesc owningType = field.OwningType; - TypeDesc fieldType = field.FieldType; + TypeDesc runtimeDeterminedOwningType = runtimeDeterminedField.OwningType; + + TypeDesc owningType = _writer.ConvertToCanonFormIfNecessary(field.OwningType, CanonicalFormKind.Specific); + TypeDesc fieldType = _writer.ConvertToCanonFormIfNecessary(field.FieldType, CanonicalFormKind.Specific); // TODO: Is this valid combination? if (!isStatic && !owningType.IsValueType && thisPtr.Kind != StackValueKind.ObjRef) throw new InvalidProgramException(); - if (field.IsStatic) - TriggerCctor(field.OwningType); + if (!runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic) + TriggerCctor(runtimeDeterminedField.OwningType); TypeDesc addressType = fieldType.MakeByRefType(); StackValueKind kind = GetStackValueKind(addressType); PushTemp(kind, addressType); - AppendCastIfNecessary(kind, addressType); - Append("&"); - - if (field.IsStatic) - { - if (!fieldType.IsValueType) - Append("__gcStatics."); - else - Append("__statics."); - Append(_writer.GetCppStaticFieldName(field)); - } - else - if (thisPtr.Kind == StackValueKind.ValueType) + if (runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic) { - throw new NotImplementedException(); + AddTypeReference(fieldType, false); + + AppendCastIfNecessary(kind, addressType); + + Append("&"); + + Append("((("); + Append(_writer.GetCppStaticsTypeName(owningType, field.HasGCStaticBase, field.IsThreadStatic)); + Append("*)"); + AppendStaticFieldGenericLookupHelperAndAddReference(runtimeDeterminedField); + Append("("); + Append(GetGenericContext()); + Append("))->"); + Append(_writer.GetCppFieldName(field)); + Append(")"); } else { - Append("(("); - Append(_writer.GetCppTypeName(owningType)); - Append("*)"); - Append(thisPtr); - Append(")->"); - Append(_writer.GetCppFieldName(field)); + AddFieldReference(field); + + AppendCastIfNecessary(kind, addressType); + + Append("&"); + + if (field.IsStatic) + { + Append(_writer.GetCppStaticsName(owningType, field.HasGCStaticBase, field.IsThreadStatic)); + Append("."); + Append(_writer.GetCppFieldName(field)); + } + else + if (thisPtr.Kind == StackValueKind.ValueType) + { + throw new NotImplementedException(); + } + else + { + Append("(("); + Append(_writer.GetCppTypeName(owningType)); + Append("*)"); + Append(thisPtr); + Append(")->"); + Append(_writer.GetCppFieldName(field)); - GetSignatureTypeNameAndAddReference(owningType); + GetSignatureTypeNameAndAddReference(owningType); + } } AppendSemicolon(); @@ -1969,49 +2710,66 @@ private void ImportAddressOfField(int token, bool isStatic) private void ImportStoreField(int token, bool isStatic) { - FieldDesc field = (FieldDesc)_methodIL.GetObject(token); - - AddFieldReference(field); + FieldDesc runtimeDeterminedField = (FieldDesc)_methodIL.GetObject(token); + FieldDesc field = (FieldDesc)_canonMethodIL.GetObject(token); var value = _stack.Pop(); var thisPtr = isStatic ? InvalidEntry.Entry : _stack.Pop(); - TypeDesc owningType = field.OwningType; - TypeDesc fieldType = field.FieldType; + TypeDesc runtimeDeterminedOwningType = runtimeDeterminedField.OwningType; + + TypeDesc owningType = _writer.ConvertToCanonFormIfNecessary(field.OwningType, CanonicalFormKind.Specific); + TypeDesc fieldType = _writer.ConvertToCanonFormIfNecessary(field.FieldType, CanonicalFormKind.Specific); // TODO: Is this valid combination? if (!isStatic && !owningType.IsValueType && thisPtr.Kind != StackValueKind.ObjRef) throw new InvalidProgramException(); - if (field.IsStatic) - TriggerCctor(field.OwningType); - - // TODO: Write barrier as necessary!!! + if (!runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic) + TriggerCctor(runtimeDeterminedField.OwningType); - AppendLine(); - if (field.IsStatic) - { - if (!fieldType.IsValueType) - Append("__gcStatics."); - else - Append("__statics."); - Append(_writer.GetCppStaticFieldName(field)); - } - else if (thisPtr.Kind == StackValueKind.ValueType) + if (runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic) { - throw new NotImplementedException(); + Append("((("); + Append(_writer.GetCppStaticsTypeName(owningType, field.HasGCStaticBase, field.IsThreadStatic)); + Append("*)"); + AppendStaticFieldGenericLookupHelperAndAddReference(runtimeDeterminedField); + Append("("); + Append(GetGenericContext()); + Append("))->"); + Append(_writer.GetCppFieldName(field)); + Append(")"); } else { - Append("(("); - Append(_writer.GetCppTypeName(owningType)); - Append("*)"); - Append(thisPtr); - Append(")->"); - Append(_writer.GetCppFieldName(field)); + AddFieldReference(field); + + // TODO: Write barrier as necessary!!! + + AppendLine(); + if (field.IsStatic) + { + Append(_writer.GetCppStaticsName(owningType, field.HasGCStaticBase, field.IsThreadStatic)); + Append("."); + Append(_writer.GetCppFieldName(field)); + } + else if (thisPtr.Kind == StackValueKind.ValueType) + { + throw new NotImplementedException(); + } + else + { + Append("(("); + Append(_writer.GetCppTypeName(owningType)); + Append("*)"); + Append(thisPtr); + Append(")->"); + Append(_writer.GetCppFieldName(field)); - GetSignatureTypeNameAndAddReference(owningType); + GetSignatureTypeNameAndAddReference(owningType); + } } + Append(" = "); if (!fieldType.IsValueType) { @@ -2127,13 +2885,14 @@ private void ImportLoadString(int token) private void ImportInitObj(int token) { - TypeDesc type = (TypeDesc)_methodIL.GetObject(token); + TypeDesc type = (TypeDesc)_canonMethodIL.GetObject(token); + var addr = _stack.Pop(); AppendLine(); Append("::memset((void*)"); Append(addr); Append(",0,sizeof("); - Append(GetSignatureTypeNameAndAddReference(type)); + Append(GetSignatureTypeNameAndAddReference(_writer.ConvertToCanonFormIfNecessary(type, CanonicalFormKind.Specific))); Append("))"); AppendSemicolon(); } @@ -2155,14 +2914,31 @@ private void ImportBox(int token) private ExpressionEntry BoxValue(TypeDesc type, StackEntry value) { string tempName = NewTempName(); + TypeDesc runtimeDeterminedType = type; + + if (type.IsRuntimeDeterminedSubtype) + type = type.ConvertToCanonForm(CanonicalFormKind.Specific); AddTypeReference(type, true); Append(GetStackValueKindCPPTypeName(StackValueKind.ObjRef, type)); Append(" "); Append(tempName); Append(" = __allocate_object("); - Append(_writer.GetCppTypeName(type)); - Append("::__getMethodTable())"); + + if (runtimeDeterminedType.IsRuntimeDeterminedSubtype) + { + Append("(MethodTable *)"); + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeDeterminedType)); + Append("("); + Append(GetGenericContext()); + Append("))"); + } + else + { + Append(_writer.GetCppTypeName(type)); + Append("::__getMethodTable())"); + } + AppendSemicolon(); string typeName = GetStackValueKindCPPTypeName(GetStackValueKind(type), type); @@ -2278,20 +3054,35 @@ private void ImportEndFinally() private void ImportNewArray(int token) { - TypeDesc type = (TypeDesc)_methodIL.GetObject(token); - TypeDesc arrayType = type.Context.GetArrayType(type); + TypeDesc runtimeDeterminedType = (TypeDesc)_methodIL.GetObject(token); + TypeDesc runtimeDeterminedArrayType = runtimeDeterminedType.MakeArrayType(); + TypeDesc type = (TypeDesc)_canonMethodIL.GetObject(token); + TypeDesc arrayType = _writer.ConvertToCanonFormIfNecessary(type.MakeArrayType(), CanonicalFormKind.Specific); var numElements = _stack.Pop(); PushTemp(StackValueKind.ObjRef, arrayType); - AddTypeReference(arrayType, true); - Append("__allocate_array("); Append(numElements); Append(", "); - Append(_writer.GetCppTypeName(arrayType)); - Append("::__getMethodTable()"); + + AddTypeReference(arrayType, true); + + if (runtimeDeterminedType.IsRuntimeDeterminedSubtype) + { + Append("(MethodTable *)"); + Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeDeterminedArrayType)); + Append("("); + Append(GetGenericContext()); + Append(")"); + } + else + { + Append(_writer.GetCppTypeName(runtimeDeterminedArrayType)); + Append("::__getMethodTable()"); + } + Append(")"); AppendSemicolon(); } @@ -2381,7 +3172,7 @@ private void ImportStoreElement(TypeDesc elementType) private void ImportAddressOfElement(int token) { - TypeDesc elementType = (TypeDesc)_methodIL.GetObject(token); + TypeDesc elementType = (TypeDesc)_canonMethodIL.GetObject(token); var index = _stack.Pop(); var arrayPtr = _stack.Pop(); @@ -2507,13 +3298,14 @@ private void ImportMkRefAny(int token) private void ImportLdToken(int token) { var ldtokenValue = _methodIL.GetObject(token); + WellKnownType ldtokenKind; string name; StackEntry value; if (ldtokenValue is TypeDesc) { ldtokenKind = WellKnownType.RuntimeTypeHandle; - AddTypeReference((TypeDesc)ldtokenValue, false); + TypeDesc type = (TypeDesc)ldtokenValue; MethodDesc helper = _typeSystemContext.GetHelperEntryPoint("LdTokenHelpers", "GetRuntimeTypeHandle"); AddMethodReference(helper); @@ -2521,12 +3313,30 @@ private void ImportLdToken(int token) name = String.Concat( _writer.GetCppTypeName(helper.OwningType), "::", - _writer.GetCppMethodName(helper), - "((intptr_t)", - _compilation.NameMangler.GetMangledTypeName((TypeDesc)ldtokenValue), - "::__getMethodTable())"); + _writer.GetCppMethodName(helper)); + + if (type.IsRuntimeDeterminedSubtype) + { + name = String.Concat( + name, + "((intptr_t)", + GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, type), + "(", + GetGenericContext(), + "))"); + } + else + { + AddTypeReference(type, false); + + name = String.Concat( + name, + "((intptr_t)", + _compilation.NameMangler.GetMangledTypeName(type), + "::__getMethodTable())"); + } - value = new LdTokenEntry(StackValueKind.ValueType, name, (TypeDesc)ldtokenValue, GetWellKnownType(ldtokenKind)); + value = new LdTokenEntry(StackValueKind.ValueType, name, type, GetWellKnownType(ldtokenKind)); } else if (ldtokenValue is FieldDesc) { @@ -2633,7 +3443,7 @@ private void ImportConstrainedPrefix(int token) { _pendingPrefix |= Prefix.Constrained; - _constrained = ResolveTypeToken(token); + _constrained = (TypeDesc)_methodIL.GetObject(token); } private void ImportNoPrefix(byte mask) @@ -2648,6 +3458,8 @@ private void ImportReadOnlyPrefix() private void TriggerCctor(TypeDesc type) { + Debug.Assert(!type.IsRuntimeDeterminedSubtype); + // TODO: Before field init MethodDesc cctor = type.GetStaticConstructor(); @@ -2656,22 +3468,32 @@ private void TriggerCctor(TypeDesc type) // TODO: Thread safety - string ctorHasRun = "__statics.__cctor_" + _writer.GetCppTypeName(type).Replace("::", "__"); + MethodDesc canonCctor = cctor.GetCanonMethodTarget(CanonicalFormKind.Specific); + + string ctorHasRun = _writer.GetCppStaticsName(type) + ".__cctor_has_run"; AppendLine(); Append("if (!" + ctorHasRun + ") {"); Indent(); AppendLine(); Append(ctorHasRun + " = true;"); AppendLine(); - Append(_writer.GetCppTypeName(cctor.OwningType)); + Append(_writer.GetCppTypeName(canonCctor.OwningType)); Append("::"); - Append(_writer.GetCppMethodName(cctor)); - Append("();"); + Append(_writer.GetCppMethodName(canonCctor)); + Append("("); + + if (canonCctor != cctor) + { + Append(_writer.GetCppTypeName(cctor.OwningType)); + Append("::__getMethodTable()"); + } + + Append(");"); Exdent(); AppendLine(); Append("}"); - AddMethodReference(cctor); + AddMethodReference(canonCctor); } private void AddTypeReference(TypeDesc type, bool constructed) @@ -2686,13 +3508,16 @@ private void AddTypeReference(TypeDesc type, bool constructed) { foreach (var field in type.GetFields()) { - AddTypeDependency(field.FieldType, false); + AddTypeDependency(_writer.ConvertToCanonFormIfNecessary(field.FieldType, CanonicalFormKind.Specific), false); } } } private void AddTypeDependency(TypeDesc type, bool constructed) { - if (type.IsPrimitive) + Debug.Assert(!type.IsRuntimeDeterminedSubtype); + + if (type.IsPrimitive || + type.IsCanonicalSubtype(CanonicalFormKind.Any) && (type.IsPointer || type.IsByRef)) { return; } @@ -2712,6 +3537,11 @@ private void AddMethodReference(MethodDesc method) _dependencies.Add(_nodeFactory.MethodEntrypoint(method)); } + private void AddCanonicalReference(MethodDesc method) + { + _dependencies.Add(_nodeFactory.CanonicalEntrypoint(method)); + } + private void AddVirtualMethodReference(MethodDesc method) { _dependencies.Add(_nodeFactory.VirtualMethodUse(method)); @@ -2719,28 +3549,34 @@ private void AddVirtualMethodReference(MethodDesc method) private void AddFieldReference(FieldDesc field) { + var owningType = field.OwningType; + + Debug.Assert(!owningType.IsRuntimeDeterminedSubtype); + if (field.IsStatic) { - var owningType = (MetadataType)field.OwningType; + var metadataType = owningType as MetadataType; Object node; if (field.IsThreadStatic) { - node = _nodeFactory.TypeThreadStaticsSymbol(owningType); + node = _nodeFactory.TypeThreadStaticsSymbol(metadataType); } else { if (field.HasGCStaticBase) - node = _nodeFactory.TypeGCStaticsSymbol(owningType); + node = _nodeFactory.TypeGCStaticsSymbol(metadataType); else - node = _nodeFactory.TypeNonGCStaticsSymbol(owningType); + node = _nodeFactory.TypeNonGCStaticsSymbol(metadataType); } // TODO: Remove once the dependencies for static fields are tracked properly - GetSignatureTypeNameAndAddReference(owningType, true); + GetSignatureTypeNameAndAddReference(metadataType, true); _dependencies.Add(node); } - AddTypeReference(field.FieldType, false); + + var fieldType = field.FieldType; + AddTypeReference(_writer.ConvertToCanonFormIfNecessary(fieldType, CanonicalFormKind.Specific), false); } private string GetSignatureTypeNameAndAddReference(TypeDesc type, bool constructed = true) diff --git a/src/ILCompiler/src/Program.cs b/src/ILCompiler/src/Program.cs index 12ca1a33886..8099f113fc9 100644 --- a/src/ILCompiler/src/Program.cs +++ b/src/ILCompiler/src/Program.cs @@ -278,7 +278,7 @@ private int Run(string[] args) // Initialize type system context // - SharedGenericsMode genericsMode = _useSharedGenerics || (!_isCppCodegen && !_isWasmCodegen) ? + SharedGenericsMode genericsMode = _useSharedGenerics || !_isWasmCodegen ? SharedGenericsMode.CanonicalReferenceTypes : SharedGenericsMode.Disabled; // TODO: compiler switch for SIMD support? @@ -450,7 +450,7 @@ private int Run(string[] args) useScanner &= !_noScanner; - bool supportsReflection = !_isWasmCodegen && !_isCppCodegen && _systemModuleName == DefaultSystemModule; + bool supportsReflection = !_isWasmCodegen && _systemModuleName == DefaultSystemModule; MetadataManager compilationMetadataManager = supportsReflection ? metadataManager : (MetadataManager)new EmptyMetadataManager(typeSystemContext); ILScanResults scanResults = null; diff --git a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ExternalReferencesTable.cs b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ExternalReferencesTable.cs index 3c6a9d382a4..7bd5bd845ab 100644 --- a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ExternalReferencesTable.cs +++ b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ExternalReferencesTable.cs @@ -105,12 +105,7 @@ unsafe public IntPtr GetIntPtrFromIndex(uint index) return (IntPtr)(_moduleHandle.ConvertRVAToPointer(rva)); } #else - if (index >= _elementsCount) - throw new BadImageFormatException(); - - // TODO: indirection through IAT - int* pRelPtr32 = &((int*)_elements)[index]; - return (IntPtr)((byte*)pRelPtr32 + *pRelPtr32); + return GetFieldAddressFromIndex(index); #endif } @@ -128,12 +123,7 @@ unsafe public IntPtr GetFunctionPointerFromIndex(uint index) return (IntPtr)(_moduleHandle.ConvertRVAToPointer(rva)); } #else - if (index >= _elementsCount) - throw new BadImageFormatException(); - - // TODO: indirection through IAT - int* pRelPtr32 = &((int*)_elements)[index]; - return (IntPtr)((byte*)pRelPtr32 + *pRelPtr32); + return GetFieldAddressFromIndex(index); #endif } @@ -161,8 +151,13 @@ unsafe public IntPtr GetFieldAddressFromIndex(uint index) throw new BadImageFormatException(); // TODO: indirection through IAT - int* pRelPtr32 = &((int*)_elements)[index]; - return (IntPtr)((byte*)pRelPtr32 + *pRelPtr32); + if (EEType.SupportsRelativePointers) + { + int* pRelPtr32 = &((int*)_elements)[index]; + return (IntPtr)((byte*)pRelPtr32 + *pRelPtr32); + } + + return (IntPtr)(((void**)_elements)[index]); } #endif