diff options
author | Jan Kotas <jkotas@microsoft.com> | 2015-12-01 19:55:48 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2015-12-15 02:46:35 +0300 |
commit | 81bcb5bf69252bcca091d1ce7f9d040d4ee1da95 (patch) | |
tree | 3e8e79c1cddc1edea85e133aac5d5254710d5a9c /src/ILCompiler.Compiler | |
parent | a812c6d5a53f666674716a4488fefd628483dcca (diff) |
Switch CppCodeGen to use dependency analysis framework for method code
Represent C++ MethodCode using DependencyNode. Data structures are not switched yet.
Diffstat (limited to 'src/ILCompiler.Compiler')
10 files changed, 447 insertions, 438 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs index 9e9ef0727..48bda0513 100644 --- a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs +++ b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs @@ -37,11 +37,6 @@ namespace ILCompiler private NodeFactory _nodeFactory; private DependencyAnalyzerBase<NodeFactory> _dependencyGraph; - private Dictionary<TypeDesc, RegisteredType> _registeredTypes = new Dictionary<TypeDesc, RegisteredType>(); - private Dictionary<MethodDesc, RegisteredMethod> _registeredMethods = new Dictionary<MethodDesc, RegisteredMethod>(); - private Dictionary<FieldDesc, RegisteredField> _registeredFields = new Dictionary<FieldDesc, RegisteredField>(); - private List<MethodDesc> _methodsThatNeedsCompilation = null; - private NameMangler _nameMangler = null; private ILCompiler.CppCodeGen.CppWriter _cppWriter = null; @@ -122,59 +117,6 @@ namespace ILCompiler } } - internal IEnumerable<RegisteredType> RegisteredTypes - { - get - { - return _registeredTypes.Values; - } - } - - internal RegisteredType GetRegisteredType(TypeDesc type) - { - RegisteredType existingRegistration; - if (_registeredTypes.TryGetValue(type, out existingRegistration)) - return existingRegistration; - - RegisteredType registration = new RegisteredType() { Type = type }; - _registeredTypes.Add(type, registration); - - // Register all base types too - var baseType = type.BaseType; - if (baseType != null) - GetRegisteredType(baseType); - - return registration; - } - - internal RegisteredMethod GetRegisteredMethod(MethodDesc method) - { - RegisteredMethod existingRegistration; - if (_registeredMethods.TryGetValue(method, out existingRegistration)) - return existingRegistration; - - RegisteredMethod registration = new RegisteredMethod() { Method = method }; - _registeredMethods.Add(method, registration); - - GetRegisteredType(method.OwningType); - - return registration; - } - - internal RegisteredField GetRegisteredField(FieldDesc field) - { - RegisteredField existingRegistration; - if (_registeredFields.TryGetValue(field, out existingRegistration)) - return existingRegistration; - - RegisteredField registration = new RegisteredField() { Field = field }; - _registeredFields.Add(field, registration); - - GetRegisteredType(field.OwningType); - - return registration; - } - private ILProvider _ilProvider = new ILProvider(); public MethodIL GetMethodIL(MethodDesc method) @@ -182,117 +124,69 @@ namespace ILCompiler return _ilProvider.GetMethodIL(method); } - private void CompileMethods() + private CorInfoImpl _corInfo; + + public void CompileSingleFile(MethodDesc mainMethod) { - var pendingMethods = _methodsThatNeedsCompilation; - _methodsThatNeedsCompilation = null; + _mainMethod = mainMethod; - foreach (MethodDesc method in pendingMethods) + NodeFactory.NameMangler = NameMangler; + + _nodeFactory = new NodeFactory(_typeSystemContext, _options.IsCppCodeGen); + + // Choose which dependency graph implementation to use based on the amount of logging requested. + if (_options.DgmlLog == null) { - _cppWriter.CompileMethod(method); + // No log uses the NoLogStrategy + _dependencyGraph = new DependencyAnalyzer<NoLogStrategy<NodeFactory>, NodeFactory>(_nodeFactory, null); } - } - - private void ExpandVirtualMethods() - { - // Take a snapshot of _registeredTypes - new registered types can be added during the expansion - foreach (var reg in _registeredTypes.Values.ToArray()) + else { - if (!reg.Constructed) - continue; - - TypeDesc declType = reg.Type; - while (declType != null) + if (_options.FullLog) { - var declReg = GetRegisteredType(declType); - if (declReg.VirtualSlots != null) - { - for (int i = 0; i < declReg.VirtualSlots.Count; i++) - { - MethodDesc declMethod = declReg.VirtualSlots[i]; - - AddMethod(VirtualFunctionResolution.FindVirtualFunctionTargetMethodOnObjectType(declMethod, reg.Type.GetClosestMetadataType())); - } - } - - declType = declType.BaseType; + // Full log uses the full log strategy + _dependencyGraph = new DependencyAnalyzer<FullGraphLogStrategy<NodeFactory>, NodeFactory>(_nodeFactory, null); + } + else + { + // Otherwise, use the first mark strategy + _dependencyGraph = new DependencyAnalyzer<FirstMarkLogStrategy<NodeFactory>, NodeFactory>(_nodeFactory, null); } } - } - private CorInfoImpl _corInfo; + _nodeFactory.AttachToDependencyGraph(_dependencyGraph); + + AddWellKnownTypes(); + AddCompilationRoots(); - public void CompileSingleFile(MethodDesc mainMethod) - { if (_options.IsCppCodeGen) { _cppWriter = new CppCodeGen.CppWriter(this); + + _dependencyGraph.ComputeDependencyRoutine += CppCodeGenComputeDependencyNodeDependencies; + + var nodes = _dependencyGraph.MarkedNodeList; + + _cppWriter.OutputCode(nodes); } else { _corInfo = new CorInfoImpl(this); - } - - _mainMethod = mainMethod; - - if (!_options.IsCppCodeGen) - { - NodeFactory.NameMangler = NameMangler; - - _nodeFactory = new NodeFactory(_typeSystemContext); - - // Choose which dependency graph implementation to use based on the amount of logging requested. - if (_options.DgmlLog == null) - { - // No log uses the NoLogStrategy - _dependencyGraph = new DependencyAnalyzer<NoLogStrategy<NodeFactory>, NodeFactory>(_nodeFactory, null); - } - else - { - if (_options.FullLog) - { - // Full log uses the full log strategy - _dependencyGraph = new DependencyAnalyzer<FullGraphLogStrategy<NodeFactory>, NodeFactory>(_nodeFactory, null); - } - else - { - // Otherwise, use the first mark strategy - _dependencyGraph = new DependencyAnalyzer<FirstMarkLogStrategy<NodeFactory>, NodeFactory>(_nodeFactory, null); - } - } - - _nodeFactory.AttachToDependencyGraph(_dependencyGraph); - - AddWellKnownTypes(); - AddCompilationRoots(); _dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies; + var nodes = _dependencyGraph.MarkedNodeList; ObjectWriter.EmitObject(OutputPath, nodes, _nodeFactory); - - if (_options.DgmlLog != null) - { - using (FileStream dgmlOutput = new FileStream(_options.DgmlLog, FileMode.Create)) - { - DgmlWriter.WriteDependencyGraphToStream(dgmlOutput, _dependencyGraph); - dgmlOutput.Flush(); - } - } } - else - { - AddWellKnownTypes(); - AddCompilationRoots(); - while (_methodsThatNeedsCompilation != null) + if (_options.DgmlLog != null) + { + using (FileStream dgmlOutput = new FileStream(_options.DgmlLog, FileMode.Create)) { - CompileMethods(); - - ExpandVirtualMethods(); + DgmlWriter.WriteDependencyGraphToStream(dgmlOutput, _dependencyGraph); + dgmlOutput.Flush(); } - - _cppWriter.OutputCode(); } } @@ -322,19 +216,12 @@ namespace ILCompiler private void AddCompilationRoot(MethodDesc method, string reason, string exportName = null) { - if (_dependencyGraph != null) - { - var methodEntryPoint = _nodeFactory.MethodEntrypoint(method); + var methodEntryPoint = _nodeFactory.MethodEntrypoint(method); - _dependencyGraph.AddRoot(methodEntryPoint, reason); + _dependencyGraph.AddRoot(methodEntryPoint, reason); - if (exportName != null) - _nodeFactory.NodeAliases.Add(methodEntryPoint, exportName); - } - else - { - AddMethod(method); - } + if (exportName != null) + _nodeFactory.NodeAliases.Add(methodEntryPoint, exportName); } private struct TypeAndMethod @@ -416,103 +303,24 @@ namespace ILCompiler } } - private void AddWellKnownTypes() + private void CppCodeGenComputeDependencyNodeDependencies(List<DependencyNodeCore<NodeFactory>> obj) { - var stringType = TypeSystemContext.GetWellKnownType(WellKnownType.String); - - // TODO: We are rooting String[] so the bootstrap code can find the EEType for making the command-line args - // string array. Once we generate the startup code in managed code, we should remove this - var arrayOfStringType = stringType.MakeArrayType(); - - if (_dependencyGraph != null) + foreach (CppMethodCodeNode methodCodeNodeNeedingCode in obj) { - _dependencyGraph.AddRoot(_nodeFactory.ConstructedTypeSymbol(stringType), "String type is always generated"); - _dependencyGraph.AddRoot(_nodeFactory.ConstructedTypeSymbol(arrayOfStringType), "String[] type is always generated"); + _cppWriter.CompileMethod(methodCodeNodeNeedingCode); } - else - { - AddType(stringType); - MarkAsConstructed(stringType); - AddType(arrayOfStringType); - MarkAsConstructed(arrayOfStringType); - } - } - - public void AddMethod(MethodDesc method) - { - RegisteredMethod reg = GetRegisteredMethod(method); - if (reg.IncludedInCompilation) - return; - reg.IncludedInCompilation = true; - - RegisteredType regType = GetRegisteredType(method.OwningType); - if (regType.Methods == null) - regType.Methods = new List<RegisteredMethod>(); - regType.Methods.Add(reg); - - if (_methodsThatNeedsCompilation == null) - _methodsThatNeedsCompilation = new List<MethodDesc>(); - _methodsThatNeedsCompilation.Add(method); - - if (_options.IsCppCodeGen) - { - // Precreate name to ensure that all types referenced by signatures are present - GetRegisteredType(method.OwningType); - var signature = method.Signature; - GetRegisteredType(signature.ReturnType); - for (int i = 0; i < signature.Length; i++) - GetRegisteredType(signature[i]); - } - } - - public void AddVirtualSlot(MethodDesc method) - { - RegisteredType reg = GetRegisteredType(method.OwningType); - - if (reg.VirtualSlots == null) - reg.VirtualSlots = new List<MethodDesc>(); - - for (int i = 0; i < reg.VirtualSlots.Count; i++) - { - if (reg.VirtualSlots[i] == method) - return; - } - - reg.VirtualSlots.Add(method); - } - - public void MarkAsConstructed(TypeDesc type) - { - GetRegisteredType(type).Constructed = true; } - public void AddType(TypeDesc type) + private void AddWellKnownTypes() { - RegisteredType reg = GetRegisteredType(type); - if (reg.IncludedInCompilation) - return; - reg.IncludedInCompilation = true; - - TypeDesc baseType = type.BaseType; - if (baseType != null) - AddType(baseType); - if (type.IsArray) - AddType(((ArrayType)type).ElementType); - } + var stringType = TypeSystemContext.GetWellKnownType(WellKnownType.String); - public void AddField(FieldDesc field) - { - RegisteredField reg = GetRegisteredField(field); - if (reg.IncludedInCompilation) - return; - reg.IncludedInCompilation = true; + _dependencyGraph.AddRoot(_nodeFactory.ConstructedTypeSymbol(stringType), "String type is always generated"); - if (_options.IsCppCodeGen) - { - // Precreate name to ensure that all types referenced by signatures are present - GetRegisteredType(field.OwningType); - GetRegisteredType(field.FieldType); - } + // TODO: We are rooting String[] so the bootstrap code can find the EEType for making the command-line args + // string array. Once we generate the startup code in managed code, we should remove this + var arrayOfStringType = stringType.MakeArrayType(); + _dependencyGraph.AddRoot(_nodeFactory.ConstructedTypeSymbol(arrayOfStringType), "String[] type is always generated"); } private Dictionary<MethodDesc, DelegateInfo> _delegateInfos = new Dictionary<MethodDesc, DelegateInfo>(); diff --git a/src/ILCompiler.Compiler/src/Compiler/DelegateInfo.cs b/src/ILCompiler.Compiler/src/Compiler/DelegateInfo.cs index cda73b020..24a2c5be4 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DelegateInfo.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DelegateInfo.cs @@ -26,9 +26,7 @@ namespace ILCompiler if (target.Signature.IsStatic) { - var shuffleThunk = new DelegateShuffleThunk(target); - compilation.AddMethod(shuffleThunk); - this.ShuffleThunk = shuffleThunk; + this.ShuffleThunk = new DelegateShuffleThunk(target); this.Ctor = systemDelegate.GetMethod("InitializeClosedStaticThunk", null); } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CppMethodCodeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CppMethodCodeNode.cs new file mode 100644 index 000000000..2aaebd8b5 --- /dev/null +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CppMethodCodeNode.cs @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics; +using Internal.TypeSystem; + +using ILCompiler.DependencyAnalysisFramework; +using System.Collections.Generic; + +namespace ILCompiler.DependencyAnalysis +{ + internal class CppMethodCodeNode : DependencyNodeCore<NodeFactory>, ISymbolNode + { + private MethodDesc _method; + private string _methodCode; + private IEnumerable<Object> _dependencies; + + public CppMethodCodeNode(MethodDesc method) + { + Debug.Assert(!method.IsAbstract); + _method = method; + } + + public void SetCode(string methodCode, IEnumerable<Object> dependencies) + { + Debug.Assert(_methodCode == null); + _methodCode = methodCode; + _dependencies = dependencies; + } + + public string CppCode + { + get + { + return _methodCode; + } + } + + public MethodDesc Method + { + get + { + return _method; + } + } + public override string GetName() + { + return ((ISymbolNode)this).MangledName; + } + + public override bool StaticDependenciesAreComputed + { + get + { + return _methodCode != null; + } + } + + string ISymbolNode.MangledName + { + get + { + return NodeFactory.NameMangler.GetMangledMethodName(_method); + } + } + + int ISymbolNode.Offset + { + get + { + return 0; + } + } + + public override bool InterestingForDynamicDependencyAnalysis + { + get + { + return false; + } + } + + public override bool HasDynamicDependencies + { + get + { + return false; + } + } + + public override bool HasConditionalStaticDependencies + { + get + { + return false; + } + } + + public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context) + { + var dependencies = new DependencyList(); + + foreach (Object node in _dependencies) + dependencies.Add(node, "CPP code "); + + return dependencies; + } + + 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.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs index 8949d6ad4..8822b099c 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs @@ -15,11 +15,13 @@ namespace ILCompiler.DependencyAnalysis { private TargetDetails _target; private CompilerTypeSystemContext _context; + private bool _cppCodeGen; - public NodeFactory(CompilerTypeSystemContext context) + public NodeFactory(CompilerTypeSystemContext context, bool cppCodeGen) { _target = context.Target; _context = context; + _cppCodeGen = cppCodeGen; CreateNodeCaches(); } @@ -109,9 +111,12 @@ namespace ILCompiler.DependencyAnalysis return new ObjectAndOffsetSymbolNode(key.Item1, key.Item2, key.Item3); }); - _methodCode = new NodeCache<MethodDesc, MethodCodeNode>((MethodDesc method) => + _methodCode = new NodeCache<MethodDesc, ISymbolNode>((MethodDesc method) => { - return new MethodCodeNode(method); + if (_cppCodeGen) + return new CppMethodCodeNode(method); + else + return new MethodCodeNode(method); }); _jumpStubs = new NodeCache<ISymbolNode, JumpStubNode>((ISymbolNode node) => @@ -250,19 +255,22 @@ namespace ILCompiler.DependencyAnalysis return _internalSymbols.GetOrAdd(new Tuple<ObjectNode, int, string>(obj, offset, name)); } - private NodeCache<MethodDesc, MethodCodeNode> _methodCode; + private NodeCache<MethodDesc, ISymbolNode> _methodCode; private NodeCache<ISymbolNode, JumpStubNode> _jumpStubs; public ISymbolNode MethodEntrypoint(MethodDesc method) { - var kind = method.DetectSpecialMethodKind(); - if (kind == SpecialMethodKind.PInvoke) + if (!_cppCodeGen) { - return _jumpStubs.GetOrAdd(ExternSymbol(method.GetPInvokeMethodMetadata().Name)); - } - else if (kind == SpecialMethodKind.RuntimeImport) - { - return ExternSymbol(((EcmaMethod)method).GetAttributeStringValue("System.Runtime", "RuntimeImportAttribute")); + var kind = method.DetectSpecialMethodKind(); + if (kind == SpecialMethodKind.PInvoke) + { + return _jumpStubs.GetOrAdd(ExternSymbol(method.GetPInvokeMethodMetadata().Name)); + } + else if (kind == SpecialMethodKind.RuntimeImport) + { + return ExternSymbol(((EcmaMethod)method).GetAttributeStringValue("System.Runtime", "RuntimeImportAttribute")); + } } return _methodCode.GetOrAdd(method); diff --git a/src/ILCompiler.Compiler/src/Compiler/RegisteredField.cs b/src/ILCompiler.Compiler/src/Compiler/RegisteredField.cs deleted file mode 100644 index 815641d79..000000000 --- a/src/ILCompiler.Compiler/src/Compiler/RegisteredField.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; - -using Internal.TypeSystem; - -namespace ILCompiler -{ - internal class RegisteredField - { - public FieldDesc Field; - - public bool IncludedInCompilation; - } -} diff --git a/src/ILCompiler.Compiler/src/Compiler/RegisteredMethod.cs b/src/ILCompiler.Compiler/src/Compiler/RegisteredMethod.cs deleted file mode 100644 index 0b9332b53..000000000 --- a/src/ILCompiler.Compiler/src/Compiler/RegisteredMethod.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; - -using Internal.TypeSystem; - -namespace ILCompiler -{ - internal class RegisteredMethod - { - public MethodDesc Method; - - public bool IncludedInCompilation; - - public Object MethodCode; - } -} diff --git a/src/ILCompiler.Compiler/src/Compiler/RegisteredType.cs b/src/ILCompiler.Compiler/src/Compiler/RegisteredType.cs deleted file mode 100644 index 66f5b44a4..000000000 --- a/src/ILCompiler.Compiler/src/Compiler/RegisteredType.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; - -using Internal.TypeSystem; - -namespace ILCompiler -{ - internal class RegisteredType - { - public TypeDesc Type; - - public bool IncludedInCompilation; - public bool Constructed; - - public string MangledSignatureName; // CppCodeGen specific - - public List<RegisteredMethod> Methods; - - public List<MethodDesc> VirtualSlots; - } -} diff --git a/src/ILCompiler.Compiler/src/CppCodeGen/CppWriter.cs b/src/ILCompiler.Compiler/src/CppCodeGen/CppWriter.cs index c90367efd..7c8ba7350 100644 --- a/src/ILCompiler.Compiler/src/CppCodeGen/CppWriter.cs +++ b/src/ILCompiler.Compiler/src/CppCodeGen/CppWriter.cs @@ -8,10 +8,13 @@ using System.IO; using System.Text; using System.Linq; +using ILCompiler.DependencyAnalysisFramework; + using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Internal.IL; +using ILCompiler.DependencyAnalysis; namespace ILCompiler.CppCodeGen { @@ -22,7 +25,7 @@ namespace ILCompiler.CppCodeGen private void SetWellKnownTypeSignatureName(WellKnownType wellKnownType, string mangledSignatureName) { var type = _compilation.TypeSystemContext.GetWellKnownType(wellKnownType); - _compilation.GetRegisteredType(type).MangledSignatureName = mangledSignatureName; + _cppSignatureNames.Add(type, mangledSignatureName); } public CppWriter(Compilation compilation) @@ -44,30 +47,27 @@ namespace ILCompiler.CppCodeGen SetWellKnownTypeSignatureName(WellKnownType.UIntPtr, "uintptr_t"); SetWellKnownTypeSignatureName(WellKnownType.Single, "float"); SetWellKnownTypeSignatureName(WellKnownType.Double, "double"); - - // TODO: For now, ensure that all types/methods referenced by unmanaged helpers are present - var stringType = _compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String); - AddInstanceFields(stringType); } + private Dictionary<TypeDesc, string> _cppSignatureNames = new Dictionary<TypeDesc, string>(); + public string GetCppSignatureTypeName(TypeDesc type) { - var reg = _compilation.GetRegisteredType(type); - - string mangledName = reg.MangledSignatureName; - if (mangledName != null) + string mangledName; + if (_cppSignatureNames.TryGetValue(type, out mangledName)) return mangledName; // TODO: Use friendly names for enums if (type.IsEnum) - mangledName = _compilation.GetRegisteredType(type.UnderlyingType).MangledSignatureName; + mangledName = GetCppSignatureTypeName(type.UnderlyingType); else mangledName = GetCppTypeName(type); if (!type.IsValueType && !type.IsByRef && !type.IsPointer) mangledName += "*"; - reg.MangledSignatureName = mangledName; + _cppSignatureNames.Add(type, mangledName); + return mangledName; } @@ -293,8 +293,10 @@ namespace ILCompiler.CppCodeGen } } - public void CompileMethod(MethodDesc method) + public void CompileMethod(CppMethodCodeNode methodCodeNodeNeedingCode) { + MethodDesc method = methodCodeNodeNeedingCode.Method; + _compilation.Log.WriteLine("Compiling " + method.ToString()); SpecialMethodKind kind = method.DetectSpecialMethodKind(); @@ -302,7 +304,8 @@ namespace ILCompiler.CppCodeGen if (kind != SpecialMethodKind.Unknown) { string specialMethodCode = CompileSpecialMethod(method, kind); - _compilation.GetRegisteredMethod(method).MethodCode = specialMethodCode; + + methodCodeNodeNeedingCode.SetCode(specialMethodCode, Array.Empty<Object>()); return; } @@ -332,16 +335,16 @@ namespace ILCompiler.CppCodeGen if (parameters != null) ilImporter.SetParameterNames(parameters); - methodCode = ilImporter.Compile(); + ilImporter.Compile(methodCodeNodeNeedingCode); } catch (Exception e) { _compilation.Log.WriteLine(e.Message + " (" + method + ")"); methodCode = GetCppMethodDeclaration(method, true) + " { throw 0xC000C000; }" + Environment.NewLine; - } - _compilation.GetRegisteredMethod(method).MethodCode = methodCode; + methodCodeNodeNeedingCode.SetCode(methodCode, Array.Empty<Object>()); + } } private TextWriter Out @@ -352,13 +355,72 @@ namespace ILCompiler.CppCodeGen } } + private Dictionary<TypeDesc, List<MethodDesc>> _methodLists; + private StringBuilder _statics; private StringBuilder _gcStatics; private StringBuilder _threadStatics; private StringBuilder _gcThreadStatics; // Base classes and valuetypes has to be emitted before they are used. - private HashSet<RegisteredType> _emittedTypes; + private HashSet<TypeDesc> _emittedTypes; + + private TypeDesc GetFieldTypeOrPlaceholder(FieldDesc field) + { + try + { + return field.FieldType; + } + catch + { + // TODO: For now, catch errors due to missing dependencies + return _compilation.TypeSystemContext.GetWellKnownType(WellKnownType.Boolean); + } + } + + private void ExpandTypes() + { + _emittedTypes = new HashSet<TypeDesc>(); + foreach (var t in _cppSignatureNames.Keys.ToArray()) + { + ExpandType(t); + } + _emittedTypes = null; + } + + private void ExpandType(TypeDesc type) + { + if (_emittedTypes.Contains(type)) + return; + _emittedTypes.Add(type); + + GetCppSignatureTypeName(type); + var baseType = type.BaseType; + if (baseType != null) + { + ExpandType(baseType); + } + + foreach (var field in type.GetFields()) + { + ExpandType(GetFieldTypeOrPlaceholder(field)); + } + + if (type.IsDelegate) + { + MethodDesc method = type.GetMethod("Invoke", null); + + var sig = method.Signature; + ExpandType(sig.ReturnType); + for (int i = 0; i < sig.Length; i++) + ExpandType(sig[i]); + } + + if (type.IsArray) + { + ExpandType(((ArrayType)type).ElementType); + } + } private void OutputTypes(bool full) { @@ -370,22 +432,20 @@ namespace ILCompiler.CppCodeGen _gcThreadStatics = new StringBuilder(); } - if (full) - _emittedTypes = new HashSet<RegisteredType>(); - foreach (var t in _compilation.RegisteredTypes.ToArray()) + _emittedTypes = new HashSet<TypeDesc>(); + foreach (var t in _cppSignatureNames.Keys) { - if (t.Type.IsByRef || t.Type.IsPointer) + if (t.IsByRef || t.IsPointer) continue; // Base class types and valuetype instantance field types may be emitted out-of-order to make them // appear before they are used. - if (_emittedTypes != null && _emittedTypes.Contains(t)) + if (_emittedTypes.Contains(t)) continue; OutputType(t, full); } - if (full) - _emittedTypes = null; + _emittedTypes = null; if (full) { @@ -420,43 +480,38 @@ namespace ILCompiler.CppCodeGen } } - private void OutputType(RegisteredType t, bool full) + private void OutputType(TypeDesc t, bool full) { - if (_emittedTypes != null) + _emittedTypes.Add(t); + + if (full) { - if (!t.Type.IsValueType) + if (!t.IsValueType) { - var baseType = t.Type.BaseType; + var baseType = t.BaseType; if (baseType != null) { - var baseRegistration = _compilation.GetRegisteredType(baseType); - if (!_emittedTypes.Contains(baseRegistration)) + if (!_emittedTypes.Contains(baseType)) { - OutputType(baseRegistration, full); + OutputType(baseType, full); } } } - foreach (var field in t.Type.GetFields()) + foreach (var field in t.GetFields()) { - if (!_compilation.GetRegisteredField(field).IncludedInCompilation) - continue; - - var fieldType = field.FieldType; + var fieldType = GetFieldTypeOrPlaceholder(field); if (fieldType.IsValueType && !fieldType.IsPrimitive && !field.IsStatic) { - var fieldTypeRegistration = _compilation.GetRegisteredType(fieldType); - if (!_emittedTypes.Contains(fieldTypeRegistration)) + if (!_emittedTypes.Contains(fieldType)) { - OutputType(fieldTypeRegistration, full); + OutputType(fieldType, full); } } } - - _emittedTypes.Add(t); } - string mangledName = GetCppTypeName(t.Type); + string mangledName = GetCppTypeName(t); int nesting = 0; int current = 0; @@ -475,48 +530,53 @@ namespace ILCompiler.CppCodeGen if (full) { Out.Write("class " + mangledName.Substring(current)); - if (!t.Type.IsValueType) + if (!t.IsValueType) { - var baseType = t.Type.BaseType; + var baseType = t.BaseType; if (baseType != null) { Out.Write(" : public " + GetCppTypeName(baseType)); } } Out.WriteLine(" { public:"); - if (t.IncludedInCompilation) + + // TODO: Enable once the dependencies are tracked for arrays + // if (((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(t)).Marked) + if (!t.IsPointer && !t.IsByRef) { Out.WriteLine("static MethodTable * __getMethodTable();"); } - if (t.VirtualSlots != null) + + List<MethodDesc> virtualSlots; + _compilation.NodeFactory.VirtualSlots.TryGetValue(t, out virtualSlots); + if (virtualSlots != null) { int baseSlots = 0; - var baseType = t.Type.BaseType; + var baseType = t.BaseType; while (baseType != null) { - var baseReg = _compilation.GetRegisteredType(baseType); - if (baseReg.VirtualSlots != null) - baseSlots += baseReg.VirtualSlots.Count; + List<MethodDesc> baseVirtualSlots; + _compilation.NodeFactory.VirtualSlots.TryGetValue(baseType, out baseVirtualSlots); + if (baseVirtualSlots != null) + baseSlots += baseVirtualSlots.Count; baseType = baseType.BaseType; } - for (int slot = 0; slot < t.VirtualSlots.Count; slot++) + for (int slot = 0; slot < virtualSlots.Count; slot++) { - MethodDesc virtualMethod = t.VirtualSlots[slot]; + MethodDesc virtualMethod = virtualSlots[slot]; Out.WriteLine(GetCodeForVirtualMethod(virtualMethod, baseSlots + slot)); } } - if (t.Type.IsDelegate) + if (t.IsDelegate) { - Out.WriteLine(GetCodeForDelegate(t.Type)); + Out.WriteLine(GetCodeForDelegate(t)); } - foreach (var field in t.Type.GetFields()) + foreach (var field in t.GetFields()) { - if (!_compilation.GetRegisteredField(field).IncludedInCompilation) - continue; if (field.IsStatic) { - TypeDesc fieldType = field.FieldType; + TypeDesc fieldType = GetFieldTypeOrPlaceholder(field); StringBuilder builder; if (!fieldType.IsValueType) { @@ -533,20 +593,20 @@ namespace ILCompiler.CppCodeGen } else { - Out.WriteLine(GetCppSignatureTypeName(field.FieldType) + " " + GetCppFieldName(field) + ";"); + Out.WriteLine(GetCppSignatureTypeName(GetFieldTypeOrPlaceholder(field)) + " " + GetCppFieldName(field) + ";"); } } - if (t.Type.GetMethod(".cctor", null) != null) + if (t.HasStaticConstructor) { - _statics.AppendLine("bool __cctor_" + GetCppTypeName(t.Type).Replace("::", "__") + ";"); + _statics.AppendLine("bool __cctor_" + GetCppTypeName(t).Replace("::", "__") + ";"); } - if (t.Methods != null) + List<MethodDesc> methodList; + if (_methodLists.TryGetValue(t, out methodList)) { - foreach (var m in t.Methods) + foreach (var m in methodList) { - if (m.IncludedInCompilation) - OutputMethod(m); + OutputMethod(m); } } Out.Write("};"); @@ -564,9 +624,9 @@ namespace ILCompiler.CppCodeGen Out.WriteLine(); } - private void OutputMethod(RegisteredMethod m) + private void OutputMethod(MethodDesc m) { - Out.WriteLine(GetCppMethodDeclaration(m.Method, false)); + Out.WriteLine(GetCppMethodDeclaration(m, false)); } private void AppendSlotTypeDef(StringBuilder sb, MethodDesc method) @@ -654,19 +714,27 @@ namespace ILCompiler.CppCodeGen if (baseType != null) AppendVirtualSlots(sb, implType, baseType); - var reg = _compilation.GetRegisteredType(declType); - if (reg.VirtualSlots != null) + List<MethodDesc> virtualSlots; + _compilation.NodeFactory.VirtualSlots.TryGetValue(declType, out virtualSlots); + if (virtualSlots != null) { - for (int i = 0; i < reg.VirtualSlots.Count; i++) + for (int i = 0; i < virtualSlots.Count; i++) { - MethodDesc declMethod = reg.VirtualSlots[i]; + MethodDesc declMethod = virtualSlots[i]; MethodDesc implMethod = VirtualFunctionResolution.FindVirtualFunctionTargetMethodOnObjectType(declMethod, implType.GetClosestMetadataType()); - sb.Append("(void*)&"); - sb.Append(GetCppTypeName(implMethod.OwningType)); - sb.Append("::"); - sb.Append(GetCppMethodName(implMethod)); - sb.Append(","); + if (implMethod.IsAbstract) + { + sb.Append("NULL,"); + } + else + { + sb.Append("(void*)&"); + sb.Append(GetCppTypeName(implMethod.OwningType)); + sb.Append("::"); + sb.Append(GetCppMethodName(implMethod)); + sb.Append(","); + } } } } @@ -676,12 +744,14 @@ namespace ILCompiler.CppCodeGen StringBuilder sb = new StringBuilder(); int totalSlots = 0; + TypeDesc t = type; while (t != null) { - var reg = _compilation.GetRegisteredType(t); - if (reg.VirtualSlots != null) - totalSlots += reg.VirtualSlots.Count; + List<MethodDesc> virtualSlots; + _compilation.NodeFactory.VirtualSlots.TryGetValue(t, out virtualSlots); + if (virtualSlots != null) + totalSlots += virtualSlots.Count; t = t.BaseType; } @@ -753,7 +823,7 @@ namespace ILCompiler.CppCodeGen sb.AppendLine("},"); // virtual slots - if (_compilation.GetRegisteredType(type).Constructed) + if (((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(type)).Marked) AppendVirtualSlots(sb, type, type); sb.AppendLine("};"); @@ -763,28 +833,42 @@ namespace ILCompiler.CppCodeGen return sb.ToString(); } - private void AddInstanceFields(TypeDesc type) + private void BuildMethodLists(IEnumerable<DependencyNode> nodes) { - foreach (var field in type.GetFields()) + _methodLists = new Dictionary<TypeDesc, List<MethodDesc>>(); + foreach (var node in nodes) { - if (!field.IsStatic) + if (node is CppMethodCodeNode) { - _compilation.AddField(field); - var fieldType = field.FieldType; - if (fieldType.IsValueType && !fieldType.IsPrimitive) - AddInstanceFields(fieldType); + CppMethodCodeNode methodCodeNode = (CppMethodCodeNode)node; + + var method = methodCodeNode.Method; + var type = method.OwningType; + + List<MethodDesc> methodList; + if (!_methodLists.TryGetValue(type, out methodList)) + { + GetCppSignatureTypeName(type); + + methodList = new List<MethodDesc>(); + _methodLists.Add(type, methodList); + } + + methodList.Add(method); + } + else + if (node is EETypeNode) + { + GetCppSignatureTypeName(((EETypeNode)node).Type); } } } - public void OutputCode() + public void OutputCode(IEnumerable<DependencyNode> nodes) { - foreach (var t in _compilation.RegisteredTypes.ToArray()) - { - // Add all instance fields for valuetype types - if (t.Type.IsValueType) - AddInstanceFields(t.Type); - } + BuildMethodLists(nodes); + + ExpandTypes(); Out.WriteLine("#include \"common.h\""); Out.WriteLine(); @@ -794,19 +878,22 @@ namespace ILCompiler.CppCodeGen OutputTypes(true); Out.WriteLine(); - foreach (var t in _compilation.RegisteredTypes) + foreach (var t in _cppSignatureNames.Keys) { - if (t.IncludedInCompilation) + // TODO: Enable once the dependencies are tracked for arrays + // if (((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(t)).Marked) + if (!t.IsPointer && !t.IsByRef) { - Out.WriteLine(GetCodeForType(t.Type)); + Out.WriteLine(GetCodeForType(t)); } - if (t.Methods != null) + List<MethodDesc> methodList; + if (_methodLists.TryGetValue(t, out methodList)) { - foreach (var m in t.Methods) + foreach (var m in methodList) { - if (m.MethodCode != null) - Out.WriteLine(m.MethodCode); + var methodCodeNode = (CppMethodCodeNode)_compilation.NodeFactory.MethodEntrypoint(m); + Out.WriteLine(methodCodeNode.CppCode); } } } diff --git a/src/ILCompiler.Compiler/src/CppCodeGen/ILToCppImporter.cs b/src/ILCompiler.Compiler/src/CppCodeGen/ILToCppImporter.cs index d147d9a7a..5c8ccb960 100644 --- a/src/ILCompiler.Compiler/src/CppCodeGen/ILToCppImporter.cs +++ b/src/ILCompiler.Compiler/src/CppCodeGen/ILToCppImporter.cs @@ -12,6 +12,8 @@ using Internal.IL.Stubs; using ILCompiler; using ILCompiler.CppCodeGen; +using ILCompiler.DependencyAnalysis; + namespace Internal.IL { public struct ILSequencePoint @@ -32,6 +34,7 @@ namespace Internal.IL internal partial class ILImporter { private Compilation _compilation; + private NodeFactory _nodeFactory; private CppWriter _writer; private TypeSystemContext _typeSystemContext; @@ -84,6 +87,7 @@ namespace Internal.IL private TypeDesc _constrained; private StringBuilder _builder = new StringBuilder(); + private ArrayBuilder<object> _dependencies = new ArrayBuilder<object>(); private class BasicBlock { @@ -106,6 +110,8 @@ namespace Internal.IL public ILImporter(Compilation compilation, CppWriter writer, MethodDesc method, MethodIL methodIL) { _compilation = compilation; + _nodeFactory = _compilation.NodeFactory; + _writer = writer; _method = method; @@ -422,7 +428,7 @@ namespace Internal.IL _builder.AppendLine(); } - public string Compile() + public void Compile(CppMethodCodeNode methodCodeNodeNeedingCode) { FindBasicBlocks(); @@ -522,7 +528,7 @@ namespace Internal.IL _builder.AppendLine("}"); - return _builder.ToString(); + methodCodeNodeNeedingCode.SetCode(_builder.ToString(), _dependencies.ToArray()); } private void StartImportingBasicBlock(BasicBlock basicBlock) @@ -612,6 +618,8 @@ namespace Internal.IL var value = Pop(); PushTemp(StackValueKind.ObjRef, type); + AddTypeReference(type, false); + Append(opcode == ILOpcode.isinst ? "__isinst_class" : "__castclass_class"); Append("("); Append(value.Value.Name); @@ -761,17 +769,17 @@ namespace Internal.IL if (method.OwningType.IsInterface) throw new NotImplementedException(); - _compilation.AddVirtualSlot(method); + _dependencies.Add(_nodeFactory.VirtualMethodUse(method)); callViaSlot = true; } } if (!callViaSlot && !delegateInvoke && !mdArrayCreate) - _compilation.AddMethod(method); + AddMethodReference(method); if (opcode == ILOpcode.newobj) - _compilation.MarkAsConstructed(retType); + AddTypeReference(retType, true); var methodSignature = method.Signature; @@ -808,8 +816,6 @@ namespace Internal.IL { if (!retType.IsValueType) { - _compilation.AddType(retType); - Append("__allocate_object("); Append(_writer.GetCppTypeName(retType)); Append("::__getMethodTable())"); @@ -817,6 +823,8 @@ namespace Internal.IL if (delegateInfo != null && delegateInfo.ShuffleThunk != null) { + AddMethodReference(delegateInfo.ShuffleThunk); + _stack[_stackTop - 2].Value.Name = temp; StringBuilder sb = new StringBuilder(); @@ -850,7 +858,6 @@ namespace Internal.IL } else if (mdArrayCreate) { - _compilation.AddType(method.OwningType); Append("RhNewMDArray"); } else @@ -931,7 +938,7 @@ namespace Internal.IL throw new NotImplementedException(); } - _compilation.AddMethod(method); + AddMethodReference(method); PushTemp(StackValueKind.NativeInt); Append("(intptr_t)&"); @@ -1393,7 +1400,7 @@ namespace Internal.IL { FieldDesc field = (FieldDesc)_methodIL.GetObject(token); - _compilation.AddField(field); + AddFieldReference(field); var thisPtr = isStatic ? new StackValue() : Pop(); @@ -1443,7 +1450,7 @@ namespace Internal.IL { FieldDesc field = (FieldDesc)_methodIL.GetObject(token); - _compilation.AddField(field); + AddFieldReference(field); var thisPtr = isStatic ? new StackValue() : Pop(); @@ -1495,7 +1502,7 @@ namespace Internal.IL { FieldDesc field = (FieldDesc)_methodIL.GetObject(token); - _compilation.AddField(field); + AddFieldReference(field); var value = Pop(); var thisPtr = isStatic ? new StackValue() : Pop(); @@ -1666,8 +1673,7 @@ namespace Internal.IL PushTemp(StackValueKind.ObjRef, type); - _compilation.AddType(type); - _compilation.MarkAsConstructed(type); + AddTypeReference(type, true); Append("__allocate_object("); Append(_writer.GetCppTypeName(type)); @@ -1778,8 +1784,7 @@ namespace Internal.IL PushTemp(StackValueKind.ObjRef, arrayType); - _compilation.AddType(arrayType); - _compilation.MarkAsConstructed(arrayType); + AddTypeReference(arrayType, true); Append("__allocate_array("); Append(numElements.Value.Name); @@ -2115,7 +2120,7 @@ namespace Internal.IL { // TODO: Before field init - MethodDesc cctor = type.GetMethod(".cctor", null); + MethodDesc cctor = type.GetStaticConstructor(); if (cctor == null) return; @@ -2128,7 +2133,50 @@ namespace Internal.IL Append(_writer.GetCppMethodName(cctor)); Append("(); }"); - _compilation.AddMethod(cctor); + AddMethodReference(cctor); + } + + private void AddTypeReference(TypeDesc type, bool constructed) + { + Object node; + + if (constructed) + node = _nodeFactory.ConstructedTypeSymbol(type); + else + node = _nodeFactory.NecessaryTypeSymbol(type); + + _dependencies.Add(node); + } + + private void AddMethodReference(MethodDesc method) + { + _dependencies.Add(_nodeFactory.MethodEntrypoint(method)); + } + + private void AddFieldReference(FieldDesc field) + { + if (field.IsStatic) + { + var owningType = (MetadataType)field.OwningType; + + Object node; + if (field.IsThreadStatic) + { + node = _nodeFactory.TypeThreadStaticsSymbol(owningType); + } + else + { + if (field.HasGCStaticBase) + node = _nodeFactory.TypeGCStaticsSymbol(owningType); + else + node = _nodeFactory.TypeNonGCStaticsSymbol(owningType); + } + + // TODO: Remove once the depedencies for static fields are tracked properly + _writer.GetCppSignatureTypeName(owningType); + + _dependencies.Add(node); + } } } } diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj index ab7735480..d0091a8f7 100644 --- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj +++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj @@ -38,9 +38,11 @@ <Compile Include="Compiler\CompilerTypeSystemContext.cs" /> <Compile Include="Compiler\DelegateInfo.cs" /> <Compile Include="Compiler\DependencyAnalysis\ArrayOfEmbeddedDataNode.cs" /> + <Compile Include="Compiler\DependencyAnalysis\CppMethodCodeNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\EETypeOptionalFieldsNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\EmbeddedObjectNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\JumpStubNode.cs" /> + <Compile Include="Compiler\DependencyAnalysis\MethodCodeNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\StringDataNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\StringIndirectionNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\Target_X64\AddrMode.cs" /> @@ -53,7 +55,6 @@ <Compile Include="Compiler\DependencyAnalysis\INodeWithDebugInfo.cs" /> <Compile Include="Compiler\DependencyAnalysis\INodeWithFrameInfo.cs" /> <Compile Include="Compiler\DependencyAnalysis\ISymbolNode.cs" /> - <Compile Include="Compiler\DependencyAnalysis\MethodCodeNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\NodeFactory.cs" /> <Compile Include="Compiler\DependencyAnalysis\NonGCStaticsNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\ObjectAndOffsetSymbolNode.cs" /> @@ -74,9 +75,6 @@ <Compile Include="Compiler\MethodExtensions.cs" /> <Compile Include="Compiler\NameMangler.cs" /> <Compile Include="Compiler\PdbSymbolProvider.cs" /> - <Compile Include="Compiler\RegisteredField.cs" /> - <Compile Include="Compiler\RegisteredMethod.cs" /> - <Compile Include="Compiler\RegisteredType.cs" /> <Compile Include="Compiler\IntrinsicMethods.cs" /> <Compile Include="Compiler\VirtualMethodCallHelper.cs" /> <Compile Include="CppCodeGen\CppWriter.cs" /> |