diff options
author | Michal Strehovský <MichalStrehovsky@users.noreply.github.com> | 2018-03-06 11:14:16 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-06 11:14:16 +0300 |
commit | bce98342633901dc6202f23597598526380af010 (patch) | |
tree | d7a97341b9861d7353daac8dcc8487ca344d691a | |
parent | 4b9c387857d9dbc9f1fe0bdb046b57c3a4499be6 (diff) |
Progress towards sealed vtable support in CppCodegen (#5495)
I wanted to get rid of the CppCodegen special casing around sealed vtables that was added last week; this became kind of tricky and I ran out of time I allocated myself for it. It seems like interface dispatch is kind of broken in general for CppCodeGen.
This has a couple changes towards the goal:
* Add TargetArchitecture.Cpp64 for CppCodegen so that we can distinguish it from x64
* This forced me to fix the misuse of x64 assembly unboxing helpers because there's no CPU emitter for Cpp64.
* Remove duplication of vtable slot calculation. The logic is different when sealed virtuals are in play. We should just use the common helper.
* Devirtualize calls to final methods. These could be in the sealed vtable which makes the dispatch tricky; just don't use the vtable.
8 files changed, 98 insertions, 27 deletions
diff --git a/src/Common/src/TypeSystem/Common/TargetDetails.cs b/src/Common/src/TypeSystem/Common/TargetDetails.cs index 31323e59b..a17a5157a 100644 --- a/src/Common/src/TypeSystem/Common/TargetDetails.cs +++ b/src/Common/src/TypeSystem/Common/TargetDetails.cs @@ -16,9 +16,10 @@ namespace Internal.TypeSystem ARM, ARMEL, ARM64, + Cpp64, X64, X86, - Wasm32 + Wasm32, } /// <summary> @@ -90,6 +91,7 @@ namespace Internal.TypeSystem { case TargetArchitecture.ARM64: case TargetArchitecture.X64: + case TargetArchitecture.Cpp64: return 8; case TargetArchitecture.ARM: case TargetArchitecture.ARMEL: @@ -204,7 +206,6 @@ namespace Internal.TypeSystem { case TargetArchitecture.ARM: case TargetArchitecture.ARMEL: - case TargetArchitecture.Wasm32: // ARM supports two alignments for objects on the GC heap (4 byte and 8 byte) if (fieldAlignment.IsIndeterminate) return LayoutInt.Indeterminate; @@ -215,8 +216,10 @@ namespace Internal.TypeSystem return new LayoutInt(8); case TargetArchitecture.X64: case TargetArchitecture.ARM64: + case TargetArchitecture.Cpp64: return new LayoutInt(8); case TargetArchitecture.X86: + case TargetArchitecture.Wasm32: return new LayoutInt(4); default: throw new NotSupportedException(); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs index 3eeb0909d..dfe887c46 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs @@ -906,7 +906,12 @@ namespace ILCompiler.DependencyAnalysis flags |= (uint)EETypeRareFlags.RequiresAlign8Flag; } - if (metadataType != null && metadataType.IsHfa) + TargetArchitecture targetArch = _type.Context.Target.Architecture; + if (metadataType != null && + (targetArch == TargetArchitecture.ARM || + targetArch == TargetArchitecture.ARMEL || + targetArch == TargetArchitecture.ARM64) && + metadataType.IsHfa) { flags |= (uint)EETypeRareFlags.IsHFAFlag; } diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs index baf0339aa..d282e1f27 100644 --- a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs +++ b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs @@ -40,8 +40,7 @@ namespace ILCompiler.DependencyAnalysis protected override IMethodNode CreateUnboxingStubNode(MethodDesc method) { - // TODO: this is wrong: this returns an assembly stub node - return new UnboxingStubNode(method, Target); + return new CppUnboxingStubNode(method); } protected override ISymbolNode CreateReadyToRunHelperNode(ReadyToRunHelperKey helperCall) diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppUnboxingStubNode.cs b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppUnboxingStubNode.cs new file mode 100644 index 000000000..916c94d9e --- /dev/null +++ b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppUnboxingStubNode.cs @@ -0,0 +1,68 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics; + +using ILCompiler.DependencyAnalysisFramework; + +using Internal.Text; +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + internal class CppUnboxingStubNode : DependencyNodeCore<NodeFactory>, IMethodNode + { + public CppUnboxingStubNode(MethodDesc method) + { + Debug.Assert(method.OwningType.IsValueType && !method.Signature.IsStatic); + Method = method; + } + + public MethodDesc Method { get; } + + public int ClassCode => 17864523; + + public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + sb.Append("unbox_").Append(nameMangler.GetMangledMethodName(Method)); + } + + public int CompareToImpl(ISortableSymbolNode other, CompilerComparer comparer) + { + return comparer.Compare(this.Method, ((CppUnboxingStubNode)other).Method); + } + + public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory) + { + return new DependencyListEntry[] { + new DependencyListEntry(factory.MethodEntrypoint(Method), "Target of unboxing") }; + } + + protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); + + public static string GetMangledName(NameMangler nameMangler, MethodDesc method) + { + return "unbox_" + nameMangler.GetMangledMethodName(method); + } + + public override bool StaticDependenciesAreComputed => true; + public override bool HasDynamicDependencies => false; + public override bool InterestingForDynamicDependencyAnalysis => false; + public override bool HasConditionalStaticDependencies => false; + + public int Offset => throw new System.NotImplementedException(); + + public bool RepresentsIndirectionCell => throw new System.NotImplementedException(); + + public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context) + { + return null; + } + public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context) + { + return null; + } + } +} diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs index ef08550b7..fb2130704 100644 --- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs +++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs @@ -894,12 +894,12 @@ namespace ILCompiler.CppCodeGen { relocCode.Append("dispatchMapModule"); } - else if(reloc.Target is UnboxingStubNode) + else if(reloc.Target is CppUnboxingStubNode) { - var method = reloc.Target as UnboxingStubNode; + var method = reloc.Target as CppUnboxingStubNode; relocCode.Append("(void*)&"); - relocCode.Append(GetCppMethodDeclarationName(method.Method.OwningType, UnboxingStubNode.GetMangledName(factory.NameMangler, method.Method), false)); + relocCode.Append(GetCppMethodDeclarationName(method.Method.OwningType, method.GetMangledName(factory.NameMangler), false)); } else { @@ -1202,23 +1202,15 @@ namespace ILCompiler.CppCodeGen if (typeNode is ConstructedEETypeNode) { - IReadOnlyList<MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(nodeType.GetClosestDefType()).Slots; + DefType closestDefType = nodeType.GetClosestDefType(); - int baseSlots = 0; - var baseType = nodeType.BaseType; - while (baseType != null) - { - IReadOnlyList<MethodDesc> baseVirtualSlots = _compilation.NodeFactory.VTable(baseType).Slots; - if (baseVirtualSlots != null) - baseSlots += baseVirtualSlots.Count; - baseType = baseType.BaseType; - } + IReadOnlyList<MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(closestDefType).Slots; - for (int slot = 0; slot < virtualSlots.Count; slot++) + foreach (MethodDesc slot in virtualSlots) { - MethodDesc virtualMethod = virtualSlots[slot]; typeDefinitions.AppendLine(); - typeDefinitions.Append(GetCodeForVirtualMethod(virtualMethod, baseSlots + slot)); + int slotNumber = VirtualMethodSlotHelper.GetVirtualMethodSlot(_compilation.NodeFactory, slot, closestDefType); + typeDefinitions.Append(GetCodeForVirtualMethod(slot, slotNumber)); } if (nodeType.IsDelegate) @@ -1242,7 +1234,7 @@ namespace ILCompiler.CppCodeGen typeDefinitions.AppendLine(); AppendCppMethodDeclaration(typeDefinitions, m, false); typeDefinitions.AppendLine(); - AppendCppMethodDeclaration(typeDefinitions, m, false, null, null, UnboxingStubNode.GetMangledName(factory.NameMangler, m)); + AppendCppMethodDeclaration(typeDefinitions, m, false, null, null, CppUnboxingStubNode.GetMangledName(factory.NameMangler, m)); } } @@ -1342,13 +1334,13 @@ namespace ILCompiler.CppCodeGen /// </summary> /// <param name="unboxingStubNode">The unboxing stub node to be output</param> /// <param name="methodImplementations">The buffer in which to write out the C++ code</param> - private void OutputUnboxingStubNode(UnboxingStubNode unboxingStubNode) + private void OutputUnboxingStubNode(CppUnboxingStubNode unboxingStubNode) { Out.WriteLine(); CppGenerationBuffer sb = new CppGenerationBuffer(); sb.AppendLine(); - AppendCppMethodDeclaration(sb, unboxingStubNode.Method, true, null, null, UnboxingStubNode.GetMangledName(_compilation.NameMangler, unboxingStubNode.Method)); + AppendCppMethodDeclaration(sb, unboxingStubNode.Method, true, null, null, unboxingStubNode.GetMangledName(_compilation.NameMangler)); sb.AppendLine(); sb.Append("{"); sb.Indent(); @@ -1405,8 +1397,8 @@ namespace ILCompiler.CppCodeGen { if (node is CppMethodCodeNode) OutputMethodNode(node as CppMethodCodeNode); - else if (node is UnboxingStubNode) - OutputUnboxingStubNode(node as UnboxingStubNode); + else if (node is CppUnboxingStubNode) + OutputUnboxingStubNode(node as CppUnboxingStubNode); } Out.Dispose(); diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs index ae062dad6..560820ad2 100644 --- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs +++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs @@ -1151,7 +1151,7 @@ namespace Internal.IL { // TODO: Null checks - if (method.IsVirtual) + if (method.IsVirtual && !method.IsFinal && !method.OwningType.IsSealed()) { // TODO: Full resolution of virtual methods if (!method.IsNewSlot) diff --git a/src/ILCompiler.CppCodeGen/src/ILCompiler.CppCodeGen.csproj b/src/ILCompiler.CppCodeGen/src/ILCompiler.CppCodeGen.csproj index 1ef83f8bd..80a2a51f2 100644 --- a/src/ILCompiler.CppCodeGen/src/ILCompiler.CppCodeGen.csproj +++ b/src/ILCompiler.CppCodeGen/src/ILCompiler.CppCodeGen.csproj @@ -32,6 +32,7 @@ <Compile Include="Compiler\CppNodeMangler.cs" /> <Compile Include="Compiler\CppCodegenCompilation.cs" /> <Compile Include="Compiler\CppCodegenCompilationBuilder.cs" /> + <Compile Include="Compiler\DependencyAnalysis\CppUnboxingStubNode.cs" /> <Compile Include="CppCodeGen\DependencyNodeIterator.cs" /> <Compile Include="CppCodeGen\EvaluationStack.cs" /> <Compile Include="CppCodeGen\CppGenerationBuffer.cs" /> diff --git a/src/ILCompiler/src/Program.cs b/src/ILCompiler/src/Program.cs index e869f7540..b86796ad6 100644 --- a/src/ILCompiler/src/Program.cs +++ b/src/ILCompiler/src/Program.cs @@ -231,6 +231,9 @@ namespace ILCompiler if (_isWasmCodegen) _targetArchitecture = TargetArchitecture.Wasm32; + else if (_isCppCodegen) + _targetArchitecture = TargetArchitecture.Cpp64; + // // Initialize type system context // |