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

GenericVirtualMethodTableNode.cs « DependencyAnalysis « Compiler « src « ILCompiler.Compiler « src - github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 18f727a6937e9aa490a688313a14f7b49c3a2242 (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
// 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.Diagnostics;
using System.Collections.Generic;

using Internal.Text;
using Internal.TypeSystem;
using Internal.NativeFormat;

namespace ILCompiler.DependencyAnalysis
{
    /// <summary>
    /// Represents a map between reflection metadata and generated method bodies.
    /// </summary>
    internal sealed class GenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode
    {
        private ObjectAndOffsetSymbolNode _endSymbol;
        private ExternalReferencesTableNode _externalReferences;
        private Dictionary<MethodDesc, Dictionary<TypeDesc, MethodDesc>> _gvmImplemenations;

        public GenericVirtualMethodTableNode(ExternalReferencesTableNode externalReferences)
        {
            _endSymbol = new ObjectAndOffsetSymbolNode(this, 0, "__gvm_table_End", true);
            _externalReferences = externalReferences;
            _gvmImplemenations = new Dictionary<MethodDesc, Dictionary<TypeDesc, MethodDesc>>();
        }

        public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
        {
            sb.Append(nameMangler.CompilationUnitPrefix).Append("__gvm_table");
        }

        public ISymbolNode EndSymbol => _endSymbol;
        public int Offset => 0;
        public override bool IsShareable => false;
        public override ObjectNodeSection Section => _externalReferences.Section;
        public override bool StaticDependenciesAreComputed => true;
        protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);

        /// <summary>
        /// Helper method to compute the dependencies that would be needed by a hashtable entry for a GVM call.
        /// This helper is used by the TypeGVMEntriesNode, which is used by the dependency analysis to compute the 
        /// GVM hashtable entries for the compiled types.
        /// The dependencies returned from this function will be reported as static dependencies of the TypeGVMEntriesNode,
        /// which we create for each type that has generic virtual methods.
        /// </summary>
        public static void GetGenericVirtualMethodImplementationDependencies(ref DependencyList dependencies, NodeFactory factory, MethodDesc callingMethod, MethodDesc implementationMethod)
        {
            Debug.Assert(!callingMethod.OwningType.IsInterface);

            if (!factory.MetadataManager.SupportsReflection)
                return;

            // Compute the open method signatures
            MethodDesc openCallingMethod = callingMethod.GetTypicalMethodDefinition();
            MethodDesc openImplementationMethod = implementationMethod.GetTypicalMethodDefinition();

            var openCallingMethodNameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(openCallingMethod);
            var openImplementationMethodNameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(openImplementationMethod);

            dependencies.Add(new DependencyListEntry(factory.NativeLayout.PlacedSignatureVertex(openCallingMethodNameAndSig), "gvm table calling method signature"));
            dependencies.Add(new DependencyListEntry(factory.NativeLayout.PlacedSignatureVertex(openImplementationMethodNameAndSig), "gvm table implementation method signature"));
        }

        private void AddGenericVirtualMethodImplementation(NodeFactory factory, MethodDesc callingMethod, MethodDesc implementationMethod)
        {
            Debug.Assert(!callingMethod.OwningType.IsInterface);

            // Compute the open method signatures
            MethodDesc openCallingMethod = callingMethod.GetTypicalMethodDefinition();
            MethodDesc openImplementationMethod = implementationMethod.GetTypicalMethodDefinition();

            // Insert open method signatures into the GVM map
            if (!_gvmImplemenations.ContainsKey(openCallingMethod))
                _gvmImplemenations[openCallingMethod] = new Dictionary<TypeDesc, MethodDesc>();

            _gvmImplemenations[openCallingMethod][openImplementationMethod.OwningType] = openImplementationMethod;
        }

        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
                return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });

            // Build the GVM table entries from the list of interesting GVMTableEntryNodes
            foreach (var interestingEntry in factory.MetadataManager.GetTypeGVMEntries())
            {
                foreach (var typeGVMEntryInfo in interestingEntry.ScanForGenericVirtualMethodEntries())
                {
                    AddGenericVirtualMethodImplementation(factory, typeGVMEntryInfo.CallingMethod, typeGVMEntryInfo.ImplementationMethod);
                }
            }

            // Ensure the native layout blob has been saved
            factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory);

            NativeWriter nativeFormatWriter = new NativeWriter();
            VertexHashtable gvmHashtable = new VertexHashtable();

            Section gvmHashtableSection = nativeFormatWriter.NewSection();
            gvmHashtableSection.Place(gvmHashtable);

            // Emit the GVM target information entries
            foreach (var gvmEntry in _gvmImplemenations)
            {
                Debug.Assert(!gvmEntry.Key.OwningType.IsInterface);

                foreach (var implementationEntry in gvmEntry.Value)
                {
                    MethodDesc callingMethod = gvmEntry.Key;
                    TypeDesc implementationType = implementationEntry.Key;
                    MethodDesc implementationMethod = implementationEntry.Value;

                    uint callingTypeId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(callingMethod.OwningType));
                    Vertex vertex = nativeFormatWriter.GetUnsignedConstant(callingTypeId);

                    uint targetTypeId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(implementationType));
                    vertex = nativeFormatWriter.GetTuple(vertex, nativeFormatWriter.GetUnsignedConstant(targetTypeId));

                    var nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(callingMethod));
                    vertex = nativeFormatWriter.GetTuple(vertex, nativeFormatWriter.GetUnsignedConstant((uint)nameAndSig.SavedVertex.VertexOffset));

                    nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(implementationMethod));
                    vertex = nativeFormatWriter.GetTuple(vertex, nativeFormatWriter.GetUnsignedConstant((uint)nameAndSig.SavedVertex.VertexOffset));

                    int hashCode = callingMethod.OwningType.GetHashCode();
                    hashCode = ((hashCode << 13) ^ hashCode) ^ implementationType.GetHashCode();

                    gvmHashtable.Append((uint)hashCode, gvmHashtableSection.Place(vertex));
                }
            }

            // Zero out the dictionary so that we AV if someone tries to insert after we're done.
            _gvmImplemenations = null;

            byte[] streamBytes = nativeFormatWriter.Save();

            _endSymbol.SetSymbolOffset(streamBytes.Length);

            return new ObjectData(streamBytes, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol });
        }

        protected internal override int Phase => (int)ObjectNodePhase.Ordered;
        public override int ClassCode => (int)ObjectNodeOrder.GenericVirtualMethodTableNode;
    }
}