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