1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Generic; 7 using System.Diagnostics; 8 9 using ILCompiler.DependencyAnalysisFramework; 10 using Internal.Text; 11 using Internal.TypeSystem; 12 13 namespace ILCompiler.DependencyAnalysis 14 { 15 public static class ProjectNDependencyBehavior 16 { 17 // Temporary static variable to enable full analysis when using the ProjectN abi 18 // When full analysis is fully supported, remove this class and field forever. 19 public static bool EnableFullAnalysis = false; 20 } 21 22 /// <summary> 23 /// Represents a symbol that is defined externally but modeled as a method 24 /// in the DependencyAnalysis infrastructure during compilation that is compiled 25 /// in the current compilation process 26 /// </summary> 27 public class NonExternMethodSymbolNode : ExternSymbolNode, IMethodBodyNodeWithFuncletSymbols, ISpecialUnboxThunkNode, IExportableSymbolNode 28 { 29 private MethodDesc _method; 30 private bool _isUnboxing; 31 private List<DependencyListEntry> _compilationDiscoveredDependencies; 32 ISymbolNode[] _funcletSymbols = Array.Empty<ISymbolNode>(); 33 bool _dependenciesQueried; 34 bool _hasCompiledBody; 35 NonExternMethodSymbolNode(NodeFactory factory, MethodDesc method, bool isUnboxing)36 public NonExternMethodSymbolNode(NodeFactory factory, MethodDesc method, bool isUnboxing) 37 : base(isUnboxing ? UnboxingStubNode.GetMangledName(factory.NameMangler, method) : 38 factory.NameMangler.GetMangledMethodName(method)) 39 { 40 _isUnboxing = isUnboxing; 41 _method = method; 42 43 // Ensure all method bodies are fully canonicalized or not at all. 44 Debug.Assert(!method.IsCanonicalMethod(CanonicalFormKind.Any) || (method.GetCanonMethodTarget(CanonicalFormKind.Specific) == method)); 45 Debug.Assert(!method.IsCanonicalMethod(CanonicalFormKind.Universal) || (method.GetCanonMethodTarget(CanonicalFormKind.Universal) == method)); 46 } 47 48 protected override string GetName(NodeFactory factory) => "Non" + base.GetName(factory); 49 GetExportForm(NodeFactory factory)50 public ExportForm GetExportForm(NodeFactory factory) 51 { 52 ExportForm exportForm = factory.CompilationModuleGroup.GetExportMethodForm(_method, IsSpecialUnboxingThunk); 53 if (exportForm == ExportForm.ByName) 54 return ExportForm.None; // Non-extern symbols exported by name are naturally handled by the linker 55 return exportForm; 56 } 57 58 public MethodDesc Method 59 { 60 get 61 { 62 return _method; 63 } 64 } 65 66 public bool IsSpecialUnboxingThunk 67 { 68 get 69 { 70 if (_isUnboxing) 71 { 72 if (!_method.HasInstantiation && _method.OwningType.IsValueType && !_method.Signature.IsStatic) 73 return _method.IsCanonicalMethod(CanonicalFormKind.Any); 74 } 75 76 return false; 77 } 78 } GetUnboxingThunkTarget(NodeFactory factory)79 public ISymbolNode GetUnboxingThunkTarget(NodeFactory factory) 80 { 81 Debug.Assert(IsSpecialUnboxingThunk); 82 83 return factory.MethodEntrypoint(_method.GetCanonMethodTarget(CanonicalFormKind.Specific), false); 84 } 85 86 public bool HasCompiledBody => _hasCompiledBody; SetHasCompiledBody()87 public void SetHasCompiledBody() 88 { 89 // This method isn't expected to be called multiple times 90 Debug.Assert(!_hasCompiledBody); 91 _hasCompiledBody = true; 92 } 93 SetFuncletCount(int funcletCount)94 public void SetFuncletCount(int funcletCount) 95 { 96 Debug.Assert(funcletCount > 0); 97 Debug.Assert(_funcletSymbols.Length == 0); 98 ISymbolNode[] funclets = new ISymbolNode[funcletCount]; 99 for (int funcletId = 1; funcletId <= funcletCount; funcletId++) 100 funclets[funcletId - 1] = new FuncletSymbol(this, funcletId); 101 _funcletSymbols = funclets; 102 } 103 AddCompilationDiscoveredDependency(IDependencyNode<NodeFactory> node, string reason)104 public void AddCompilationDiscoveredDependency(IDependencyNode<NodeFactory> node, string reason) 105 { 106 Debug.Assert(!_dependenciesQueried); 107 if (_compilationDiscoveredDependencies == null) 108 _compilationDiscoveredDependencies = new List<DependencyListEntry>(); 109 _compilationDiscoveredDependencies.Add(new DependencyNodeCore<NodeFactory>.DependencyListEntry(node, reason)); 110 } 111 112 public override bool StaticDependenciesAreComputed 113 { 114 get 115 { 116 if (ProjectNDependencyBehavior.EnableFullAnalysis) 117 return HasCompiledBody; 118 else 119 return true; 120 } 121 } 122 123 ISymbolNode[] IMethodBodyNodeWithFuncletSymbols.FuncletSymbols 124 { 125 get 126 { 127 return _funcletSymbols; 128 } 129 } 130 GetStaticDependencies(NodeFactory factory)131 public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory) 132 { 133 _dependenciesQueried = true; 134 DependencyList dependencies = null; 135 CodeBasedDependencyAlgorithm.AddDependenciesDueToMethodCodePresence(ref dependencies, factory, _method); 136 137 if (_compilationDiscoveredDependencies != null) 138 { 139 dependencies = dependencies ?? new DependencyList(); 140 dependencies.AddRange(_compilationDiscoveredDependencies); 141 } 142 143 if (MethodAssociatedDataNode.MethodHasAssociatedData(factory, this)) 144 { 145 dependencies = dependencies ?? new DependencyList(); 146 dependencies.Add(new DependencyListEntry(factory.MethodAssociatedData(this), "Method associated data")); 147 } 148 149 return dependencies; 150 } 151 152 private class FuncletSymbol : ISymbolNodeWithFuncletId 153 { FuncletSymbol(NonExternMethodSymbolNode methodSymbol, int funcletId)154 public FuncletSymbol(NonExternMethodSymbolNode methodSymbol, int funcletId) 155 { 156 _funcletId = funcletId; 157 _methodSymbol = methodSymbol; 158 } 159 160 private int _funcletId; 161 private NonExternMethodSymbolNode _methodSymbol; 162 163 public ISymbolNode AssociatedMethodSymbol => _methodSymbol; 164 165 public int FuncletId => _funcletId; 166 167 public int Offset => 0; 168 169 public bool RepresentsIndirectionCell => false; 170 public bool InterestingForDynamicDependencyAnalysis => false; 171 public bool HasDynamicDependencies => false; 172 public bool HasConditionalStaticDependencies => false; 173 public bool StaticDependenciesAreComputed => true; 174 public bool Marked => _methodSymbol.Marked; AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)175 public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) 176 { 177 _methodSymbol.AppendMangledName(nameMangler, sb); 178 } 179 GetConditionalStaticDependencies(NodeFactory context)180 public IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context) 181 { 182 return null; 183 } 184 GetStaticDependencies(NodeFactory context)185 public IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context) 186 { 187 return null; 188 } 189 SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context)190 public IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context) 191 { 192 return null; 193 } 194 } 195 } 196 } 197