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

GenericDictionaryNode.cs « DependencyAnalysis « Compiler « src « ILCompiler.Compiler « src - github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 211ac3a1f1e1a3b24405b6233cb2bd71dbd15ce9 (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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
// 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 Internal.Text;
using Internal.TypeSystem;

namespace ILCompiler.DependencyAnalysis
{
    /// <summary>
    /// Represents a generic dictionary for a concrete generic type instantiation
    /// or generic method instantiation. The dictionary is used from canonical code
    /// at runtime to look up runtime artifacts that depend on the concrete
    /// context the generic type or method was instantiated with.
    /// </summary>
    public abstract class GenericDictionaryNode : ObjectNode, IExportableSymbolNode, ISortableSymbolNode
    {
        private readonly NodeFactory _factory;

        protected abstract TypeSystemContext Context { get; }

        public abstract TypeSystemEntity OwningEntity { get; }

        public abstract Instantiation TypeInstantiation { get; }

        public abstract Instantiation MethodInstantiation { get; }

        public abstract DictionaryLayoutNode GetDictionaryLayout(NodeFactory factory);
        
        public sealed override bool StaticDependenciesAreComputed => true;

        public sealed override bool IsShareable => true;

        int ISymbolNode.Offset => 0;

        public abstract ExportForm GetExportForm(NodeFactory factory);

        public abstract void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb);

        protected abstract int HeaderSize { get; }

        int ISymbolDefinitionNode.Offset => HeaderSize;

        public override ObjectNodeSection Section => GetDictionaryLayout(_factory).DictionarySection(_factory);

        public GenericDictionaryNode(NodeFactory factory)
        {
            _factory = factory;
        }

        public sealed override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
            builder.AddSymbol(this);
            builder.RequireInitialPointerAlignment();

            DictionaryLayoutNode layout = GetDictionaryLayout(factory);

            // Node representing the generic dictionary layout might be one of two kinds:
            // With fixed slots, or where slots are added as we're expanding the graph.
            // If it's the latter, we can't touch the collection of slots before the graph expansion
            // is complete (relocsOnly == false). It's someone else's responsibility
            // to make sure the dependencies are properly generated.
            // If this is a dictionary layout with fixed slots, it's the responsibility of
            // each dictionary to ensure the targets are marked.
            if (layout.HasFixedSlots || !relocsOnly)
            {
                // TODO: pass the layout we already have to EmitDataInternal
                EmitDataInternal(ref builder, factory, relocsOnly);
            }

            return builder.ToObjectData();
        }

        protected virtual void EmitDataInternal(ref ObjectDataBuilder builder, NodeFactory factory, bool fixedLayoutOnly)
        {
            DictionaryLayoutNode layout = GetDictionaryLayout(factory);
            layout.EmitDictionaryData(ref builder, factory, this, fixedLayoutOnly: fixedLayoutOnly);
        }

        protected sealed override string GetName(NodeFactory factory)
        {
            return this.GetMangledName(factory.NameMangler);
        }

        public override int ClassCode => ClassCode;

        public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
        {
            return CompareToImpl((ObjectNode)other, comparer);
        }
    }

    public sealed class TypeGenericDictionaryNode : GenericDictionaryNode
    {
        private TypeDesc _owningType;

        public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
        {
            sb.Append(nameMangler.NodeMangler.TypeGenericDictionary(_owningType));
        }

        protected override int HeaderSize => 0;
        public override Instantiation TypeInstantiation => _owningType.Instantiation;
        public override Instantiation MethodInstantiation => new Instantiation();
        protected override TypeSystemContext Context => _owningType.Context;
        public override TypeSystemEntity OwningEntity => _owningType;
        public override ExportForm GetExportForm(NodeFactory factory) => factory.CompilationModuleGroup.GetExportTypeFormDictionary(OwningType);
        public TypeDesc OwningType => _owningType;

        public override DictionaryLayoutNode GetDictionaryLayout(NodeFactory factory)
        {
            return factory.GenericDictionaryLayout(_owningType.ConvertToCanonForm(CanonicalFormKind.Specific));
        }

        public override bool HasConditionalStaticDependencies => true;


        protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
        {
            DependencyList result = new DependencyList();

            // Include the layout as a dependency if the canonical type isn't imported
            TypeDesc canonicalOwningType = _owningType.ConvertToCanonForm(CanonicalFormKind.Specific);
            if (factory.CompilationModuleGroup.ContainsType(canonicalOwningType) || !factory.CompilationModuleGroup.ShouldReferenceThroughImportTable(canonicalOwningType))
                result.Add(GetDictionaryLayout(factory), "Layout");

            // Lazy generic use of the Activator.CreateInstance<T> heuristic requires tracking type parameters that are used in lazy generics.
            if (factory.LazyGenericsPolicy.UsesLazyGenerics(_owningType))
            {
                foreach (var arg in _owningType.Instantiation)
                {
                    // Skip types that do not have a default constructor (not interesting).
                    if (arg.IsValueType || arg.GetDefaultConstructor() == null || !ConstructedEETypeNode.CreationAllowed(arg))
                        continue;

                    result.Add(new DependencyListEntry(
                        factory.ConstructedTypeSymbol(arg.ConvertToCanonForm(CanonicalFormKind.Specific)),
                        "Default constructor for lazy generics"));
                }
            }

            return result;
        }

        public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory)
        {
            // The generic dictionary layout is shared between all the canonically equivalent
            // instantiations. We need to track the dependencies of all canonical method bodies
            // that use the same dictionary layout.
            foreach (var method in _owningType.GetAllMethods())
            {
                if (!EETypeNode.MethodHasNonGenericILMethodBody(method))
                    continue;

                // If a canonical method body was compiled, we need to track the dictionary
                // dependencies in the context of the concrete type that owns this dictionary.
                yield return new CombinedDependencyListEntry(
                    factory.ShadowConcreteMethod(method),
                    factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific)),
                    "Generic dictionary dependency");
            }
        }

        public TypeGenericDictionaryNode(TypeDesc owningType, NodeFactory factory)
            : base(factory)
        {
            Debug.Assert(!owningType.IsCanonicalSubtype(CanonicalFormKind.Any));
            Debug.Assert(!owningType.IsRuntimeDeterminedSubtype);
            Debug.Assert(owningType.HasInstantiation);
            Debug.Assert(owningType.ConvertToCanonForm(CanonicalFormKind.Specific) != owningType);

            _owningType = owningType;
        }

        public override int ClassCode => 889700584;

        public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
        {
            return comparer.Compare(_owningType, ((TypeGenericDictionaryNode)other)._owningType);
        }
    }

    public sealed class MethodGenericDictionaryNode : GenericDictionaryNode
    {
        private MethodDesc _owningMethod;

        public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
        {
            sb.Append(nameMangler.NodeMangler.MethodGenericDictionary(_owningMethod));
        }
        protected override int HeaderSize => _owningMethod.Context.Target.PointerSize;
        public override Instantiation TypeInstantiation => _owningMethod.OwningType.Instantiation;
        public override Instantiation MethodInstantiation => _owningMethod.Instantiation;
        protected override TypeSystemContext Context => _owningMethod.Context;
        public override TypeSystemEntity OwningEntity => _owningMethod;
        public override ExportForm GetExportForm(NodeFactory factory) => factory.CompilationModuleGroup.GetExportMethodDictionaryForm(OwningMethod);
        public MethodDesc OwningMethod => _owningMethod;

        protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
        {
            DependencyList dependencies = new DependencyList();

            MethodDesc canonicalTarget = _owningMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
            if (factory.CompilationModuleGroup.ContainsMethodBody(canonicalTarget, false))
                dependencies.Add(GetDictionaryLayout(factory), "Layout");

            GenericMethodsHashtableNode.GetGenericMethodsHashtableDependenciesForMethod(ref dependencies, factory, _owningMethod);

            factory.InteropStubManager.AddMarshalAPIsGenericDependencies(ref dependencies, factory, _owningMethod);

            // Lazy generic use of the Activator.CreateInstance<T> heuristic requires tracking type parameters that are used in lazy generics.
            if (factory.LazyGenericsPolicy.UsesLazyGenerics(_owningMethod))
            {
                foreach (var arg in _owningMethod.OwningType.Instantiation)
                {
                    // Skip types that do not have a default constructor (not interesting).
                    if (arg.IsValueType || arg.GetDefaultConstructor() == null || !ConstructedEETypeNode.CreationAllowed(arg))
                        continue;

                    dependencies.Add(new DependencyListEntry(
                        factory.ConstructedTypeSymbol(arg.ConvertToCanonForm(CanonicalFormKind.Specific)),
                        "Default constructor for lazy generics"));
                }
                foreach (var arg in _owningMethod.Instantiation)
                {
                    // Skip types that do not have a default constructor (not interesting).
                    if (arg.IsValueType || arg.GetDefaultConstructor() == null || !ConstructedEETypeNode.CreationAllowed(arg))
                        continue;

                    dependencies.Add(new DependencyListEntry(
                        factory.ConstructedTypeSymbol(arg.ConvertToCanonForm(CanonicalFormKind.Specific)),
                        "Default constructor for lazy generics"));
                }
            }

            // Make sure the dictionary can also be populated
            dependencies.Add(factory.ShadowConcreteMethod(_owningMethod), "Dictionary contents");

            return dependencies;
        }

        public override DictionaryLayoutNode GetDictionaryLayout(NodeFactory factory)
        {
            return factory.GenericDictionaryLayout(_owningMethod.GetCanonMethodTarget(CanonicalFormKind.Specific));
        }

        protected override void EmitDataInternal(ref ObjectDataBuilder builder, NodeFactory factory, bool fixedLayoutOnly)
        {
            // Method generic dictionaries get prefixed by the hash code of the owning method
            // to allow quick lookups of additional details by the type loader.

            builder.EmitInt(_owningMethod.GetHashCode());
            if (builder.TargetPointerSize == 8)
                builder.EmitInt(0);

            Debug.Assert(builder.CountBytes == ((ISymbolDefinitionNode)this).Offset);

            // Lazy method dictionaries are generated by the compiler, but they have no entries within them. (They are used solely to identify the exact method)
            // The dictionary layout may be filled in by various needs for generic lookups, but those are handled in a lazy fashion.
            if (factory.LazyGenericsPolicy.UsesLazyGenerics(OwningMethod))
                return;

            base.EmitDataInternal(ref builder, factory, fixedLayoutOnly);
        }

        public MethodGenericDictionaryNode(MethodDesc owningMethod, NodeFactory factory)
            : base(factory)
        {
            Debug.Assert(!owningMethod.IsSharedByGenericInstantiations);
            Debug.Assert(owningMethod.HasInstantiation);
            Debug.Assert(owningMethod.GetCanonMethodTarget(CanonicalFormKind.Specific) != owningMethod);

            _owningMethod = owningMethod;
        }

        public override int ClassCode => -1245704203;

        public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
        {
            return comparer.Compare(_owningMethod, ((MethodGenericDictionaryNode)other)._owningMethod);
        }
    }
}