Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

CppCodeGen: implement shared generics and support generic virtual methods #6467

Merged
merged 2 commits into from
Oct 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis
/// <summary>
/// Represents a hashtable of all type blocked from reflection.
/// </summary>
internal sealed class BlockReflectionTypeMapNode : ObjectNode, ISymbolDefinitionNode
public sealed class BlockReflectionTypeMapNode : ObjectNode, ISymbolDefinitionNode
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do all these things types need to be public now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is forced by CppCodegen living in a separate assembly and having to special cases these node types in the CppWriter. I never really liked that that's where we ended up with for CppWriter (the other object writers only deal with ObjectNode and don't have to be aware of the specific type).

It might be nice at some point to see if we can make CppWriter more general purpose so that it doesn't have to be aware of specific node types. But that's a future nice to have.

{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ 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
/// </summary>
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not be ending up with canonical EETypes for MdArrays - the template type loader doesn't need templates for these because there's nothing generic about them (they don't implement the generic interfaces that normal arrays do, such as IEnumerable<T>, etc.).

What stack are you hitting this assert from?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hitting following stacktrace:

Compiling [Hello]Hello.Program+B.M<__Canon>(__Canon)
AddTypeReference owningType: [S.P.CoreLib]System.__Canon[,]
Assertion Failed

   at ILCompiler.DependencyAnalysis.CanonicalEETypeNode..ctor(NodeFactory factory, TypeDesc type) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs:line 29
   at ILCompiler.DependencyAnalysis.NodeFactory.<CreateNodeCaches>b__36_1(TypeDesc type) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs:line 194
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at ILCompiler.DependencyAnalysis.NodeFactory.NodeCache`2.GetOrAdd(TKey key) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs:line 150
   at ILCompiler.DependencyAnalysis.NodeFactory.ConstructedTypeSymbol(TypeDesc type) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs:line 527
   at Internal.IL.ILImporter.AddTypeDependency(TypeDesc type, Boolean constructed) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs:line 3233
   at Internal.IL.ILImporter.AddTypeReference(TypeDesc type, Boolean constructed) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs:line 3211
   at Internal.IL.ILImporter.ImportNewObjArray(TypeDesc owningType, MethodDesc method) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs:line 1174
   at Internal.IL.ILImporter.ImportCall(ILOpcode opcode, Int32 token) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs:line 1290
   at Internal.IL.ILImporter.ImportBasicBlock(BasicBlock basicBlock) in /media/kbaladurin/data/dotnet/forked/corert/src/Common/src/TypeSystem/IL/ILImporter.cs:line 616
   at Internal.IL.ILImporter.ImportBasicBlocks() in /media/kbaladurin/data/dotnet/forked/corert/src/Common/src/TypeSystem/IL/ILImporter.cs:line 327
   at Internal.IL.ILImporter.Compile(CppMethodCodeNode methodCodeNodeNeedingCode) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs:line 758
   at ILCompiler.CppCodeGen.CppWriter.CompileMethod(CppMethodCodeNode methodCodeNodeNeedingCode) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs:line 553
   at ILCompiler.CppCodegenCompilation.ComputeDependencyNodeDependencies(List`1 obj) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilation.cs:line 71
   at ILCompiler.DependencyAnalysisFramework.DependencyAnalyzer`2.ComputeDependencies(List`1 deferredStaticDependencies) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.DependencyAnalysisFramework/src/DependencyAnalyzer.cs:line 139
   at ILCompiler.DependencyAnalysisFramework.DependencyAnalyzer`2.ComputeMarkedNodes() in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.DependencyAnalysisFramework/src/DependencyAnalyzer.cs:line 262
   at ILCompiler.CppCodegenCompilation.CompileInternal(String outputFile, ObjectDumper dumper) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilation.cs:line 47
   at ILCompiler.Compilation.ILCompiler.ICompilation.Compile(String outputFile, ObjectDumper dumper) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler.Compiler/src/Compiler/Compilation.cs:line 333
   at ILCompiler.Program.Run(String[] args) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler/src/Program.cs:line 514
   at ILCompiler.Program.Main(String[] args) in /media/kbaladurin/data/dotnet/forked/corert/src/ILCompiler/src/Program.cs:line 670

when compiling this method:

public override void M<T>(T t)
{
    T[,] a = new T[2, 2];
    System.Console.WriteLine("Virtual B " + t + " " + a);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change the assert to !type.IsMdArray || factory.Target.Abi == TargetAbi.CppCodegen. Generating these for MdArrays still results in useless data structures, but due to how CppCodegen needs to operate, we'll have to live with it there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Thank you!

Debug.Assert(!type.IsMdArray || factory.Target.Abi == TargetAbi.CppCodegen);
}

public override bool StaticDependenciesAreComputed => true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis
/// <summary>
/// Hashtable of all exact (non-canonical) generic method instantiations compiled in the module.
/// </summary>
internal sealed class ExactMethodInstantiationsNode : ObjectNode, ISymbolDefinitionNode
public sealed class ExactMethodInstantiationsNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,24 @@ 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)
{
delta = (int)((uint)delta | IndirectionConstants.RVAPointsToIndirection);
}
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis
/// <summary>
/// Represents a hashtable of all compiled generic method instantiations
/// </summary>
internal sealed class GenericMethodsHashtableNode : ObjectNode, ISymbolDefinitionNode
public sealed class GenericMethodsHashtableNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis
/// <summary>
/// Hashtable of all generic method templates used by the TypeLoader at runtime
/// </summary>
internal sealed class GenericMethodsTemplateMap : ObjectNode, ISymbolDefinitionNode
public sealed class GenericMethodsTemplateMap : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis
/// <summary>
/// Represents a hashtable of all compiled generic type instantiations
/// </summary>
internal sealed class GenericTypesHashtableNode : ObjectNode, ISymbolDefinitionNode
public sealed class GenericTypesHashtableNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace ILCompiler.DependencyAnalysis
/// <summary>
/// Represents a map of generic virtual method implementations.
/// </summary>
internal sealed class GenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode
public sealed class GenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace ILCompiler.DependencyAnalysis
/// <summary>
/// Represents a map between reflection metadata and generated method bodies.
/// </summary>
internal sealed class InterfaceGenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode
public sealed class InterfaceGenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/// </summary>
internal sealed class MetadataNode : ObjectNode, ISymbolDefinitionNode
public sealed class MetadataNode : ObjectNode, ISymbolDefinitionNode
{
ObjectAndOffsetSymbolNode _endSymbol;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis
/// <summary>
/// Native layout info blob.
/// </summary>
internal sealed class NativeLayoutInfoNode : ObjectNode, ISymbolDefinitionNode
public sealed class NativeLayoutInfoNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ namespace ILCompiler.DependencyAnalysis
/// <summary>
/// The node is used in ProjectX to represent a canonical type that does not have a vtable.
/// </summary>
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);
Debug.Assert(!type.IsMdArray || factory.Target.Abi == TargetAbi.CppCodegen);
}

protected override ISymbolNode GetBaseTypeNode(NodeFactory factory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis
/// <summary>
/// Represents a map between EETypes and metadata records within the <see cref="MetadataNode"/>.
/// </summary>
internal sealed class TypeMetadataMapNode : ObjectNode, ISymbolDefinitionNode
public sealed class TypeMetadataMapNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace ILCompiler.DependencyAnalysis
/// <summary>
/// Represents a node containing information necessary at runtime to locate type's thread static base.
/// </summary>
internal class TypeThreadStaticIndexNode : ObjectNode, ISymbolDefinitionNode
public class TypeThreadStaticIndexNode : ObjectNode, ISymbolDefinitionNode
{
private MetadataType _type;

Expand Down Expand Up @@ -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)
Expand Down
17 changes: 15 additions & 2 deletions src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,22 @@ protected override void CompileInternal(string outputFile, ObjectDumper dumper)

protected override void ComputeDependencyNodeDependencies(List<DependencyNodeCore<NodeFactory>> 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);
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/ILCompiler.CppCodeGen/src/Compiler/CppNodeMangler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
foreach (Object node in _dependencies)
dependencies.Add(node, "CPP code ");

CodeBasedDependencyAlgorithm.AddDependenciesDueToMethodCodePresence(ref dependencies, factory, _method);

return dependencies;
}

Expand Down
Loading