Skip to content
This repository was archived by the owner on Nov 1, 2020. It is now read-only.

Commit d0bb358

Browse files
committed
Interface dispatch support
Emit the supporting data structures for interface dispatch: - Interface dispatch cell for each call site providing the resolution function entry point as well as the interface type and interface method slot number - Interface map on EETypes specifying the list of interfaces they implement - Dispatch map that provides, for each type, the lookup rows for interface type, interface method slot, and implementing method's VTable slot - Dispatch map table that provides dispatch map pointers (the index into this table is stored on an EEType instead of a pointer to the map for space savings) Added a work-around in the runtime to provide access to the dispatch map table until full module headers are implemented
1 parent 3ce25bb commit d0bb358

File tree

22 files changed

+576
-97
lines changed

22 files changed

+576
-97
lines changed

src/Common/src/TypeSystem/Common/TypeDesc.MethodImpls.cs renamed to src/Common/src/TypeSystem/Common/InstantiatedType.MethodImpls.cs

Lines changed: 10 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,47 +5,6 @@
55

66
namespace Internal.TypeSystem
77
{
8-
public struct MethodImplRecord
9-
{
10-
public MethodDesc Decl;
11-
public MethodDesc Body;
12-
}
13-
14-
// MethodImpl api surface for types.
15-
public partial class MetadataType
16-
{
17-
/// <summary>
18-
/// Compute an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type.
19-
/// May be expensive.
20-
/// </summary>
21-
protected abstract MethodImplRecord[] ComputeVirtualMethodImplsForType();
22-
23-
private MethodImplRecord[] _allVirtualMethodImplsForType;
24-
/// <summary>
25-
/// Get an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type.
26-
/// Expected to cache results so this api can be used repeatedly.
27-
/// </summary>
28-
public MethodImplRecord[] VirtualMethodImplsForType
29-
{
30-
get
31-
{
32-
if (_allVirtualMethodImplsForType == null)
33-
{
34-
_allVirtualMethodImplsForType = ComputeVirtualMethodImplsForType();
35-
}
36-
37-
return _allVirtualMethodImplsForType;
38-
}
39-
}
40-
41-
/// <summary>
42-
/// Get an array of MethodImpls where the Decl method matches by name with the specified name.
43-
/// </summary>
44-
/// <param name="name"></param>
45-
/// <returns></returns>
46-
public abstract MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name);
47-
}
48-
498
// Implementation of MethodImpl api surface implemented without metadata access.
509
public partial class InstantiatedType
5110
{
@@ -63,7 +22,16 @@ private MethodImplRecord[] InstantiateMethodImpls(MethodImplRecord[] uninstMetho
6322

6423
for (int i = 0; i < uninstMethodImpls.Length; i++)
6524
{
66-
instMethodImpls[i].Decl = _typeDef.Context.GetMethodForInstantiatedType(uninstMethodImpls[i].Decl, this);
25+
var implTypeInstantiated = uninstMethodImpls[i].Decl.OwningType.InstantiateSignature(this.Instantiation, new Instantiation());
26+
if (implTypeInstantiated is InstantiatedType)
27+
{
28+
instMethodImpls[i].Decl = _typeDef.Context.GetMethodForInstantiatedType(uninstMethodImpls[i].Decl.GetTypicalMethodDefinition(), (InstantiatedType)implTypeInstantiated);
29+
}
30+
else
31+
{
32+
instMethodImpls[i].Decl = uninstMethodImpls[i].Decl;
33+
}
34+
6735
instMethodImpls[i].Body = _typeDef.Context.GetMethodForInstantiatedType(uninstMethodImpls[i].Body, this);
6836
}
6937

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
6+
namespace Internal.TypeSystem
7+
{
8+
public struct MethodImplRecord
9+
{
10+
public MethodDesc Decl;
11+
public MethodDesc Body;
12+
}
13+
14+
// MethodImpl api surface for types.
15+
public partial class MetadataType
16+
{
17+
/// <summary>
18+
/// Compute an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type.
19+
/// May be expensive.
20+
/// </summary>
21+
protected abstract MethodImplRecord[] ComputeVirtualMethodImplsForType();
22+
23+
private MethodImplRecord[] _allVirtualMethodImplsForType;
24+
/// <summary>
25+
/// Get an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type.
26+
/// Expected to cache results so this api can be used repeatedly.
27+
/// </summary>
28+
public MethodImplRecord[] VirtualMethodImplsForType
29+
{
30+
get
31+
{
32+
if (_allVirtualMethodImplsForType == null)
33+
{
34+
_allVirtualMethodImplsForType = ComputeVirtualMethodImplsForType();
35+
}
36+
37+
return _allVirtualMethodImplsForType;
38+
}
39+
}
40+
41+
/// <summary>
42+
/// Get an array of MethodImpls where the Decl method matches by name with the specified name.
43+
/// </summary>
44+
/// <param name="name"></param>
45+
/// <returns></returns>
46+
public abstract MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name);
47+
}
48+
}

src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ public override bool StaticDependenciesAreComputed
108108
}
109109
}
110110

111+
public void SetDispatchMapIndex(uint index)
112+
{
113+
_optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldsElement.DispatchMap, index);
114+
}
115+
111116
int ISymbolNode.Offset
112117
{
113118
get
@@ -137,8 +142,9 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
137142
objData.EmitZeroPointer();
138143
return objData.ToObjectData();
139144
}
140-
145+
141146
ComputeOptionalEETypeFields(factory);
147+
142148
if (null == _optionalFieldsNode)
143149
{
144150
_optionalFieldsNode = factory.EETypeOptionalFields(_optionalFieldsBuilder);
@@ -155,6 +161,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
155161
if (_constructed)
156162
{
157163
OutputVirtualSlots(factory, ref objData, _type, _type);
164+
OutputInterfaceMap(factory, ref objData);
158165
OutputFinalizerMethod(factory, ref objData);
159166
OutputOptionalFields(factory, ref objData);
160167
OutputNullableTypeParameter(factory, ref objData);
@@ -163,6 +170,18 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
163170
return objData.ToObjectData();
164171
}
165172

173+
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
174+
{
175+
DependencyList dependencyList = new DependencyNodeCore<NodeFactory>.DependencyList();
176+
if (_type is MetadataType && _constructed)
177+
{
178+
dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map");
179+
}
180+
181+
dependencyList.Add(factory.EETypeOptionalFields(_optionalFieldsBuilder), "EEType optional fields");
182+
return dependencyList;
183+
}
184+
166185
public override bool HasConditionalStaticDependencies
167186
{
168187
get
@@ -179,6 +198,11 @@ public override bool HasConditionalStaticDependencies
179198
return true;
180199
}
181200

201+
// If the type implements at least one interface, calls against that interface could result in this type's
202+
// implementation being used.
203+
if (_type.RuntimeInterfaces.Length > 0)
204+
return true;
205+
182206
return false;
183207
}
184208
}
@@ -195,6 +219,24 @@ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDep
195219
yield return new DependencyNodeCore<NodeFactory>.CombinedDependencyListEntry(factory.MethodEntrypoint(impl), factory.VirtualMethodUse(decl), "Virtual method");
196220
}
197221
}
222+
223+
// Add conditional dependencies for interface methods the type implements. For example, if the type T implements
224+
// interface IFoo which has a method M1, add a dependency on T.M1 dependent on IFoo.M1 being called, since it's
225+
// possible for any IFoo object to actually be an instance of T.
226+
foreach (DefType interfaceType in _type.RuntimeInterfaces)
227+
{
228+
Debug.Assert(interfaceType.IsInterface);
229+
230+
foreach (MethodDesc interfaceMethod in interfaceType.GetMethods())
231+
{
232+
Debug.Assert(interfaceMethod.IsVirtual);
233+
MethodDesc implMethod = VirtualFunctionResolution.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, _type.GetClosestMetadataType());
234+
if (implMethod != null)
235+
{
236+
yield return new DependencyNodeCore<NodeFactory>.CombinedDependencyListEntry(factory.VirtualMethodUse(implMethod), factory.ReadyToRunHelper(ReadyToRunHelperId.InterfaceDispatch, interfaceMethod), "Interface method");
237+
}
238+
}
239+
}
198240
}
199241
}
200242

@@ -335,9 +377,7 @@ private void OutputVirtualSlotAndInterfaceCount(NodeFactory factory, ref ObjectD
335377
}
336378

337379
objData.EmitShort(checked((short)virtualSlotCount));
338-
339-
// Todo: Number of slots of EEInterfaceInfo when we add interface support
340-
objData.EmitShort(0);
380+
objData.EmitShort(checked((short)_type.RuntimeInterfaces.Length));
341381
}
342382

343383
private void OutputVirtualSlots(NodeFactory factory, ref ObjectDataBuilder objData, TypeDesc implType, TypeDesc declType)
@@ -364,6 +404,14 @@ private void OutputVirtualSlots(NodeFactory factory, ref ObjectDataBuilder objDa
364404
}
365405
}
366406

407+
private void OutputInterfaceMap(NodeFactory factory, ref ObjectDataBuilder objData)
408+
{
409+
foreach (var itf in _type.RuntimeInterfaces)
410+
{
411+
objData.EmitPointerReloc(factory.NecessaryTypeSymbol(itf));
412+
}
413+
}
414+
367415
private void OutputFinalizerMethod(NodeFactory factory, ref ObjectDataBuilder objData)
368416
{
369417
MethodDesc finalizerMethod = _type.GetFinalizer();
@@ -391,12 +439,10 @@ private void OutputNullableTypeParameter(NodeFactory factory, ref ObjectDataBuil
391439
}
392440

393441
/// <summary>
394-
/// Populate the OptionalFieldsRuntimeBuilder if any optional fields are required. Returns true iff
395-
/// at least one optional field was set.
442+
/// Populate the OptionalFieldsRuntimeBuilder if any optional fields are required.
396443
/// </summary>
397444
private void ComputeOptionalEETypeFields(NodeFactory factory)
398445
{
399-
// Todo: DispatchMap table index when we support interface dispatch maps
400446
ComputeRareFlags();
401447
ComputeNullableValueOffset();
402448
ComputeICastableVirtualMethodSlots(factory);

src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeOptionalFieldsNode.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,21 @@ public override string GetName()
5656
return ((ISymbolNode)this).MangledName;
5757
}
5858

59+
public override bool ShouldSkipEmittingObjectNode(NodeFactory factory)
60+
{
61+
return !_fieldBuilder.IsAtLeastOneFieldUsed();
62+
}
63+
5964
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
6065
{
6166
ObjectDataBuilder objData = new ObjectDataBuilder(factory);
6267
objData.RequirePointerAlignment();
6368
objData.DefinedSymbols.Add(this);
64-
objData.EmitBytes(_fieldBuilder.GetBytes());
69+
70+
if (!relocsOnly)
71+
{
72+
objData.EmitBytes(_fieldBuilder.GetBytes());
73+
}
6574

6675
return objData.ToObjectData();
6776
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Internal.TypeSystem;
5+
using System;
6+
using System.Diagnostics;
7+
8+
namespace ILCompiler.DependencyAnalysis
9+
{
10+
class InterfaceDispatchCellNode : ObjectNode, ISymbolNode
11+
{
12+
MethodDesc _targetMethod;
13+
14+
public InterfaceDispatchCellNode(MethodDesc targetMethod)
15+
{
16+
Debug.Assert(targetMethod.OwningType.IsInterface);
17+
_targetMethod = targetMethod;
18+
}
19+
20+
public string MangledName
21+
{
22+
get
23+
{
24+
return "__InterfaceDispatchCell_" + NodeFactory.NameMangler.GetMangledMethodName(_targetMethod);
25+
}
26+
}
27+
28+
public override string GetName()
29+
{
30+
return ((ISymbolNode)this).MangledName;
31+
}
32+
33+
public int Offset
34+
{
35+
get
36+
{
37+
return 0;
38+
}
39+
}
40+
41+
public override string Section
42+
{
43+
get
44+
{
45+
return "data";
46+
}
47+
}
48+
49+
public override bool StaticDependenciesAreComputed
50+
{
51+
get
52+
{
53+
return true;
54+
}
55+
}
56+
57+
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
58+
{
59+
ObjectDataBuilder objData = new ObjectDataBuilder(factory);
60+
// The interface dispatch cell has an alignment requirement of 2 * [Pointer size] as part of the
61+
// synchronization mechanism of the two values in the runtime.
62+
objData.Alignment = _targetMethod.Context.Target.PointerSize * 2;
63+
objData.DefinedSymbols.Add(this);
64+
65+
objData.EmitPointerReloc(factory.ExternSymbol("RhpInitialDynamicInterfaceDispatch"));
66+
67+
// The second cell field uses the two lower-order bits to communicate the contents.
68+
// We add 1 to signal IDC_CachePointerIsInterfacePointer. See src\Native\Runtime\inc\rhbinder.h.
69+
objData.EmitPointerReloc(factory.NecessaryTypeSymbol(_targetMethod.OwningType), 1);
70+
71+
// End the run of dispatch cells
72+
objData.EmitZeroPointer();
73+
74+
int interfaceMethodSlot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, _targetMethod);
75+
if (factory.Target.PointerSize == 8)
76+
{
77+
objData.EmitLong(interfaceMethodSlot);
78+
}
79+
else
80+
{
81+
throw new NotImplementedException();
82+
}
83+
84+
return objData.ToObjectData();
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)