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

SealedVTableNode.cs « DependencyAnalysis « Compiler « src « ILCompiler.Compiler « src - github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: dac6d8dbc8cd8073f89139bb2220b59aded3473b (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
// 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 Internal.Text;
using Internal.TypeSystem;

namespace ILCompiler.DependencyAnalysis
{
    public class SealedVTableNode : ObjectNode, ISymbolDefinitionNode
    {
        private readonly TypeDesc _type;
        private List<MethodDesc> _sealedVTableEntries;

        public SealedVTableNode(TypeDesc type)
        {
            // Multidimensional arrays should not get a sealed vtable or a dispatch map. Runtime should use the 
            // sealed vtable and dispatch map of the System.Array basetype instead.
            // Pointer arrays also follow the same path
            Debug.Assert(!type.IsArrayTypeWithoutGenericInterfaces());
            Debug.Assert(!type.IsRuntimeDeterminedSubtype);

            _type = type;
        }

        protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);

        public override ObjectNodeSection Section => _type.Context.Target.IsWindows ? ObjectNodeSection.FoldableReadOnlyDataSection : ObjectNodeSection.DataSection;

        public virtual void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
        {
            sb.Append(nameMangler.CompilationUnitPrefix + "__SealedVTable_" + nameMangler.NodeMangler.EEType(_type));
        }

        int ISymbolNode.Offset => 0;
        int ISymbolDefinitionNode.Offset => 0;
        public override bool IsShareable => EETypeNode.IsTypeNodeShareable(_type);
        public override bool StaticDependenciesAreComputed => true;

        /// <summary>
        /// Returns the number of sealed vtable slots on the type. This API should only be called after successfully 
        /// building the sealed vtable slots.
        /// </summary>
        public int NumSealedVTableEntries
        {
            get
            {
                if (_sealedVTableEntries == null)
                    throw new NotSupportedException();

                return _sealedVTableEntries.Count;
            }
        }

        /// <summary>
        /// Returns the slot of a method in the sealed vtable, or -1 if not found. This API should only be called after 
        /// successfully building the sealed vtable slots.
        /// </summary>
        public int ComputeSealedVTableSlot(MethodDesc method)
        {
            if (_sealedVTableEntries == null)
                throw new NotSupportedException();

            for (int i = 0; i < _sealedVTableEntries.Count; i++)
            {
                if (_sealedVTableEntries[i] == method)
                    return i;
            }

            return -1;
        }

        public bool BuildSealedVTableSlots(NodeFactory factory, bool relocsOnly)
        {
            // Sealed vtable already built
            if (_sealedVTableEntries != null)
                return true;

            TypeDesc declType = _type.GetClosestDefType();

            // It's only okay to touch the actual list of slots if we're in the final emission phase
            // or the vtable is not built lazily.
            if (relocsOnly && !factory.VTable(declType).HasFixedSlots)
                return false;

            _sealedVTableEntries = new List<MethodDesc>();

            IReadOnlyList<MethodDesc> virtualSlots = factory.VTable(declType).Slots;

            for (int i = 0; i < virtualSlots.Count; i++)
            {
                MethodDesc implMethod = declType.FindVirtualFunctionTargetMethodOnObjectType(virtualSlots[i]);

                if (implMethod.CanMethodBeInSealedVTable())
                    _sealedVTableEntries.Add(implMethod);
            }

            // Catch any runtime interface collapsing. We shouldn't have any
            Debug.Assert(declType.RuntimeInterfaces.Length == declType.GetTypeDefinition().RuntimeInterfaces.Length);

            for (int interfaceIndex = 0; interfaceIndex < declType.RuntimeInterfaces.Length; interfaceIndex++)
            {
                var interfaceType = declType.RuntimeInterfaces[interfaceIndex];
                var interfaceDefinitionType = declType.GetTypeDefinition().RuntimeInterfaces[interfaceIndex];

                virtualSlots = factory.VTable(interfaceType).Slots;

                for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++)
                {
                    MethodDesc declMethod = virtualSlots[interfaceMethodSlot];
                    if (!interfaceType.IsTypeDefinition)
                        declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceDefinitionType);

                    var implMethod = declType.GetTypeDefinition().ResolveInterfaceMethodToVirtualMethodOnType(declMethod);

                    // Interface methods first implemented by a base type in the hierarchy will return null for the implMethod (runtime interface
                    // dispatch will walk the inheritance chain).
                    if (implMethod != null && implMethod.CanMethodBeInSealedVTable() && !implMethod.OwningType.HasSameTypeDefinition(declType))
                    {
                        TypeDesc implType = declType;
                        while (!implType.HasSameTypeDefinition(implMethod.OwningType))
                            implType = implType.BaseType;

                        MethodDesc targetMethod = implMethod;
                        if (!implType.IsTypeDefinition)
                            targetMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(implMethod.GetTypicalMethodDefinition(), (InstantiatedType)implType);

                        _sealedVTableEntries.Add(targetMethod);
                    }
                }
            }

            return true;
        }

        public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
        {
            ObjectDataBuilder objData = new ObjectDataBuilder(factory, relocsOnly);
            objData.RequireInitialAlignment(4);
            objData.AddSymbol(this);

            if (BuildSealedVTableSlots(factory, relocsOnly))
            {
                for (int i = 0; i < _sealedVTableEntries.Count; i++)
                {
                    MethodDesc canonImplMethod = _sealedVTableEntries[i].GetCanonMethodTarget(CanonicalFormKind.Specific);
                    IMethodNode relocTarget = factory.MethodEntrypoint(canonImplMethod, _sealedVTableEntries[i].OwningType.IsValueType);

                    if (factory.Target.SupportsRelativePointers)
                        objData.EmitReloc(relocTarget, RelocType.IMAGE_REL_BASED_RELPTR32);
                    else
                        objData.EmitPointerReloc(relocTarget);
                }
            }

            return objData.ToObjectData();
        }

        public override int ClassCode => 1632890252;
        public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
        {
            return comparer.Compare(_type, ((SealedVTableNode)other)._type);
        }
    }
}