Welcome to mirror list, hosted at ThFree Co, Russian Federation.

NonExternMethodSymbolNode.cs « DependencyAnalysis « Compiler « src « ILCompiler.Compiler « src - github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 6be5e9456f3c5d13a3d7381173313a49b68abb4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
// 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;
using System.Collections.Generic;
using System.Diagnostics;

using ILCompiler.DependencyAnalysisFramework;
using Internal.Text;
using Internal.TypeSystem;

namespace ILCompiler.DependencyAnalysis
{
    public static class ProjectNDependencyBehavior
    {
        // Temporary static variable to enable full analysis when using the ProjectN abi
        // When full analysis is fully supported, remove this class and field forever.
        public static bool EnableFullAnalysis = false;
    }
    
    /// <summary>
    /// Represents a symbol that is defined externally but modeled as a method
    /// in the DependencyAnalysis infrastructure during compilation that is compiled 
    /// in the current compilation process
    /// </summary>
    public class NonExternMethodSymbolNode : ExternSymbolNode, IMethodBodyNodeWithFuncletSymbols, ISpecialUnboxThunkNode, IExportableSymbolNode
    {
        private MethodDesc _method;
        private bool _isUnboxing;
        private List<DependencyListEntry> _compilationDiscoveredDependencies;
        ISymbolNode[] _funcletSymbols = Array.Empty<ISymbolNode>();
        bool _dependenciesQueried;
        bool _hasCompiledBody;
        private HashSet<GenericLookupResult> _floatingGenericLookupResults;

        public NonExternMethodSymbolNode(NodeFactory factory, MethodDesc method, bool isUnboxing)
             : base(isUnboxing ? UnboxingStubNode.GetMangledName(factory.NameMangler, method) :
                  factory.NameMangler.GetMangledMethodName(method))
        {
            _isUnboxing = isUnboxing;
            _method = method;

            // Ensure all method bodies are fully canonicalized or not at all.
            Debug.Assert(!method.IsCanonicalMethod(CanonicalFormKind.Any) || (method.GetCanonMethodTarget(CanonicalFormKind.Specific) == method));
            Debug.Assert(!method.IsCanonicalMethod(CanonicalFormKind.Universal) || (method.GetCanonMethodTarget(CanonicalFormKind.Universal) == method));
        }

        protected override string GetName(NodeFactory factory) => "Non" + base.GetName(factory);

        public ExportForm GetExportForm(NodeFactory factory)
        {
            ExportForm exportForm = factory.CompilationModuleGroup.GetExportMethodForm(_method, IsSpecialUnboxingThunk);
            if (exportForm == ExportForm.ByName)
                return ExportForm.None; // Non-extern symbols exported by name are naturally handled by the linker
            return exportForm;
        }

        public MethodDesc Method
        {
            get
            {
                return _method;
            }
        }

        public bool IsSpecialUnboxingThunk
        {
            get
            {
                if (_isUnboxing)
                {
                    if (!_method.HasInstantiation && _method.OwningType.IsValueType && !_method.Signature.IsStatic)
                        return _method.IsCanonicalMethod(CanonicalFormKind.Any);
                }

                return false;
            }
        }
        public ISymbolNode GetUnboxingThunkTarget(NodeFactory factory)
        {
            Debug.Assert(IsSpecialUnboxingThunk);

            return factory.MethodEntrypoint(_method.GetCanonMethodTarget(CanonicalFormKind.Specific), false);
        }

        public bool HasCompiledBody => _hasCompiledBody;
        public void SetHasCompiledBody()
        {
            // This method isn't expected to be called multiple times
            Debug.Assert(!_hasCompiledBody);
            _hasCompiledBody = true;
        }

        public void SetFuncletCount(int funcletCount)
        {
            Debug.Assert(funcletCount > 0);
            Debug.Assert(_funcletSymbols.Length == 0);
            ISymbolNode[] funclets = new ISymbolNode[funcletCount];
            for (int funcletId = 1; funcletId <= funcletCount; funcletId++)
                funclets[funcletId - 1] = new FuncletSymbol(this, funcletId);
            _funcletSymbols = funclets;
        }

        public void DeferFloatingGenericLookup(GenericLookupResult lookupResult)
        {
            if (_floatingGenericLookupResults == null)
                _floatingGenericLookupResults = new HashSet<GenericLookupResult>();
            _floatingGenericLookupResults.Add(lookupResult);
        }

        protected override void OnMarked(NodeFactory factory)
        {
            // Commit all floating generic lookups associated with the method when the method
            // is proved not dead.
            if (_floatingGenericLookupResults != null)
            {
                Debug.Assert(_method.IsCanonicalMethod(CanonicalFormKind.Any));
                TypeSystemEntity canonicalOwner = _method.HasInstantiation ? (TypeSystemEntity)_method : (TypeSystemEntity)_method.OwningType;
                DictionaryLayoutNode dictLayout = factory.GenericDictionaryLayout(canonicalOwner);

                foreach (var lookupResult in _floatingGenericLookupResults)
                {
                    dictLayout.EnsureEntry(lookupResult);
                }
            }
        }

        public void AddCompilationDiscoveredDependency(IDependencyNode<NodeFactory> node, string reason)
        {
            Debug.Assert(!_dependenciesQueried);
            if (_compilationDiscoveredDependencies == null)
                _compilationDiscoveredDependencies = new List<DependencyListEntry>();
            _compilationDiscoveredDependencies.Add(new DependencyNodeCore<NodeFactory>.DependencyListEntry(node, reason));
        }

        public override bool StaticDependenciesAreComputed
        {
            get
            {
                if (ProjectNDependencyBehavior.EnableFullAnalysis)
                    return HasCompiledBody;
                else
                    return true;
            }
        }

        ISymbolNode[] IMethodBodyNodeWithFuncletSymbols.FuncletSymbols
        {
            get
            {
                return _funcletSymbols;
            }
        }
        
        public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
        {
            _dependenciesQueried = true;
            DependencyList dependencies = null;
            CodeBasedDependencyAlgorithm.AddDependenciesDueToMethodCodePresence(ref dependencies, factory, _method);

            if (_compilationDiscoveredDependencies != null)
            {
                dependencies = dependencies ?? new DependencyList();
                dependencies.AddRange(_compilationDiscoveredDependencies);
            }

            if (MethodAssociatedDataNode.MethodHasAssociatedData(factory, this))
            {
                dependencies = dependencies ?? new DependencyList();
                dependencies.Add(new DependencyListEntry(factory.MethodAssociatedData(this), "Method associated data"));
            }

            return dependencies;
        }

        public override int ClassCode => -2124588118;

        public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
        {
            NonExternMethodSymbolNode otherMethod = (NonExternMethodSymbolNode)other;
            var result = _isUnboxing.CompareTo(otherMethod._isUnboxing);
            return result != 0 ? result : comparer.Compare(_method, otherMethod._method);
        }

        private class FuncletSymbol : ISymbolNodeWithFuncletId
        {
            public FuncletSymbol(NonExternMethodSymbolNode methodSymbol, int funcletId)
            {
                _funcletId = funcletId;
                _methodSymbol = methodSymbol;
            }

            private int _funcletId;
            private NonExternMethodSymbolNode _methodSymbol;

            public ISymbolNode AssociatedMethodSymbol => _methodSymbol;

            public int FuncletId => _funcletId;

            public int Offset => 0;

            public bool RepresentsIndirectionCell => false;
            public bool InterestingForDynamicDependencyAnalysis => false;
            public bool HasDynamicDependencies => false;
            public bool HasConditionalStaticDependencies => false;
            public bool StaticDependenciesAreComputed => true;
            public bool Marked => _methodSymbol.Marked;
            public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
            {
                _methodSymbol.AppendMangledName(nameMangler, sb);
            }

            public IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context)
            {
                return null;
            }

            public IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context)
            {
                return null;
            }

            public IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context)
            {
                return null;
            }
        }
    }
}