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

Commit

Permalink
Merge pull request #626 from nattress/interface_dispatch
Browse files Browse the repository at this point in the history
Interface dispatch support
  • Loading branch information
nattress committed Jan 14, 2016
2 parents d86c7e7 + 69d12d9 commit 811a323
Show file tree
Hide file tree
Showing 23 changed files with 579 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,6 @@

namespace Internal.TypeSystem
{
public struct MethodImplRecord
{
public MethodDesc Decl;
public MethodDesc Body;
}

// MethodImpl api surface for types.
public partial class MetadataType
{
/// <summary>
/// Compute an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type.
/// May be expensive.
/// </summary>
protected abstract MethodImplRecord[] ComputeVirtualMethodImplsForType();

private MethodImplRecord[] _allVirtualMethodImplsForType;
/// <summary>
/// Get an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type.
/// Expected to cache results so this api can be used repeatedly.
/// </summary>
public MethodImplRecord[] VirtualMethodImplsForType
{
get
{
if (_allVirtualMethodImplsForType == null)
{
_allVirtualMethodImplsForType = ComputeVirtualMethodImplsForType();
}

return _allVirtualMethodImplsForType;
}
}

/// <summary>
/// Get an array of MethodImpls where the Decl method matches by name with the specified name.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public abstract MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name);
}

// Implementation of MethodImpl api surface implemented without metadata access.
public partial class InstantiatedType
{
Expand All @@ -63,7 +22,16 @@ private MethodImplRecord[] InstantiateMethodImpls(MethodImplRecord[] uninstMetho

for (int i = 0; i < uninstMethodImpls.Length; i++)
{
instMethodImpls[i].Decl = _typeDef.Context.GetMethodForInstantiatedType(uninstMethodImpls[i].Decl, this);
var implTypeInstantiated = uninstMethodImpls[i].Decl.OwningType.InstantiateSignature(this.Instantiation, new Instantiation());
if (implTypeInstantiated is InstantiatedType)
{
instMethodImpls[i].Decl = _typeDef.Context.GetMethodForInstantiatedType(uninstMethodImpls[i].Decl.GetTypicalMethodDefinition(), (InstantiatedType)implTypeInstantiated);
}
else
{
instMethodImpls[i].Decl = uninstMethodImpls[i].Decl;
}

instMethodImpls[i].Body = _typeDef.Context.GetMethodForInstantiatedType(uninstMethodImpls[i].Body, this);
}

Expand Down
48 changes: 48 additions & 0 deletions src/Common/src/TypeSystem/Common/MetadataType.MethodImpls.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;

namespace Internal.TypeSystem
{
public struct MethodImplRecord
{
public MethodDesc Decl;
public MethodDesc Body;
}

// MethodImpl api surface for types.
public partial class MetadataType
{
/// <summary>
/// Compute an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type.
/// May be expensive.
/// </summary>
protected abstract MethodImplRecord[] ComputeVirtualMethodImplsForType();

private MethodImplRecord[] _allVirtualMethodImplsForType;
/// <summary>
/// Get an array of all MethodImpls that pertain to overriding virtual (non-interface methods) on this type.
/// Expected to cache results so this api can be used repeatedly.
/// </summary>
public MethodImplRecord[] VirtualMethodImplsForType
{
get
{
if (_allVirtualMethodImplsForType == null)
{
_allVirtualMethodImplsForType = ComputeVirtualMethodImplsForType();
}

return _allVirtualMethodImplsForType;
}
}

/// <summary>
/// Get an array of MethodImpls where the Decl method matches by name with the specified name.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public abstract MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ public override bool StaticDependenciesAreComputed
}
}

public void SetDispatchMapIndex(uint index)
{
_optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldsElement.DispatchMap, index);
}

int ISymbolNode.Offset
{
get
Expand Down Expand Up @@ -137,8 +142,9 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
objData.EmitZeroPointer();
return objData.ToObjectData();
}

ComputeOptionalEETypeFields(factory);

if (null == _optionalFieldsNode)
{
_optionalFieldsNode = factory.EETypeOptionalFields(_optionalFieldsBuilder);
Expand All @@ -155,6 +161,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
if (_constructed)
{
OutputVirtualSlots(factory, ref objData, _type, _type);
OutputInterfaceMap(factory, ref objData);
OutputFinalizerMethod(factory, ref objData);
OutputOptionalFields(factory, ref objData);
OutputNullableTypeParameter(factory, ref objData);
Expand All @@ -163,6 +170,18 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
return objData.ToObjectData();
}

protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
{
DependencyList dependencyList = new DependencyNodeCore<NodeFactory>.DependencyList();
if (_type is MetadataType && _constructed)
{
dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map");
}

dependencyList.Add(factory.EETypeOptionalFields(_optionalFieldsBuilder), "EEType optional fields");
return dependencyList;
}

public override bool HasConditionalStaticDependencies
{
get
Expand All @@ -179,6 +198,11 @@ public override bool HasConditionalStaticDependencies
return true;
}

// If the type implements at least one interface, calls against that interface could result in this type's
// implementation being used.
if (_type.RuntimeInterfaces.Length > 0)
return true;

return false;
}
}
Expand All @@ -195,6 +219,24 @@ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDep
yield return new DependencyNodeCore<NodeFactory>.CombinedDependencyListEntry(factory.MethodEntrypoint(impl), factory.VirtualMethodUse(decl), "Virtual method");
}
}

// Add conditional dependencies for interface methods the type implements. For example, if the type T implements
// interface IFoo which has a method M1, add a dependency on T.M1 dependent on IFoo.M1 being called, since it's
// possible for any IFoo object to actually be an instance of T.
foreach (DefType interfaceType in _type.RuntimeInterfaces)
{
Debug.Assert(interfaceType.IsInterface);

foreach (MethodDesc interfaceMethod in interfaceType.GetMethods())
{
Debug.Assert(interfaceMethod.IsVirtual);
MethodDesc implMethod = VirtualFunctionResolution.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod, _type.GetClosestMetadataType());
if (implMethod != null)
{
yield return new DependencyNodeCore<NodeFactory>.CombinedDependencyListEntry(factory.VirtualMethodUse(implMethod), factory.ReadyToRunHelper(ReadyToRunHelperId.InterfaceDispatch, interfaceMethod), "Interface method");
}
}
}
}
}

Expand Down Expand Up @@ -335,9 +377,7 @@ private void OutputVirtualSlotAndInterfaceCount(NodeFactory factory, ref ObjectD
}

objData.EmitShort(checked((short)virtualSlotCount));

// Todo: Number of slots of EEInterfaceInfo when we add interface support
objData.EmitShort(0);
objData.EmitShort(checked((short)_type.RuntimeInterfaces.Length));
}

private void OutputVirtualSlots(NodeFactory factory, ref ObjectDataBuilder objData, TypeDesc implType, TypeDesc declType)
Expand All @@ -364,6 +404,14 @@ private void OutputVirtualSlots(NodeFactory factory, ref ObjectDataBuilder objDa
}
}

private void OutputInterfaceMap(NodeFactory factory, ref ObjectDataBuilder objData)
{
foreach (var itf in _type.RuntimeInterfaces)
{
objData.EmitPointerReloc(factory.NecessaryTypeSymbol(itf));
}
}

private void OutputFinalizerMethod(NodeFactory factory, ref ObjectDataBuilder objData)
{
MethodDesc finalizerMethod = _type.GetFinalizer();
Expand Down Expand Up @@ -391,12 +439,10 @@ private void OutputNullableTypeParameter(NodeFactory factory, ref ObjectDataBuil
}

/// <summary>
/// Populate the OptionalFieldsRuntimeBuilder if any optional fields are required. Returns true iff
/// at least one optional field was set.
/// Populate the OptionalFieldsRuntimeBuilder if any optional fields are required.
/// </summary>
private void ComputeOptionalEETypeFields(NodeFactory factory)
{
// Todo: DispatchMap table index when we support interface dispatch maps
ComputeRareFlags();
ComputeNullableValueOffset();
ComputeICastableVirtualMethodSlots(factory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,21 @@ public override string GetName()
return ((ISymbolNode)this).MangledName;
}

public override bool ShouldSkipEmittingObjectNode(NodeFactory factory)
{
return !_fieldBuilder.IsAtLeastOneFieldUsed();
}

public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
ObjectDataBuilder objData = new ObjectDataBuilder(factory);
objData.RequirePointerAlignment();
objData.DefinedSymbols.Add(this);
objData.EmitBytes(_fieldBuilder.GetBytes());

if (!relocsOnly)
{
objData.EmitBytes(_fieldBuilder.GetBytes());
}

return objData.ToObjectData();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Internal.TypeSystem;
using System;
using System.Diagnostics;

namespace ILCompiler.DependencyAnalysis
{
class InterfaceDispatchCellNode : ObjectNode, ISymbolNode
{
MethodDesc _targetMethod;

public InterfaceDispatchCellNode(MethodDesc targetMethod)
{
Debug.Assert(targetMethod.OwningType.IsInterface);
_targetMethod = targetMethod;
}

public string MangledName
{
get
{
return "__InterfaceDispatchCell_" + NodeFactory.NameMangler.GetMangledMethodName(_targetMethod);
}
}

public override string GetName()
{
return ((ISymbolNode)this).MangledName;
}

public int Offset
{
get
{
return 0;
}
}

public override string Section
{
get
{
return "data";
}
}

public override bool StaticDependenciesAreComputed
{
get
{
return true;
}
}

public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
ObjectDataBuilder objData = new ObjectDataBuilder(factory);
// The interface dispatch cell has an alignment requirement of 2 * [Pointer size] as part of the
// synchronization mechanism of the two values in the runtime.
objData.Alignment = _targetMethod.Context.Target.PointerSize * 2;
objData.DefinedSymbols.Add(this);

objData.EmitPointerReloc(factory.ExternSymbol("RhpInitialDynamicInterfaceDispatch"));

// The second cell field uses the two lower-order bits to communicate the contents.
// We add 1 to signal IDC_CachePointerIsInterfacePointer. See src\Native\Runtime\inc\rhbinder.h.
objData.EmitPointerReloc(factory.NecessaryTypeSymbol(_targetMethod.OwningType), 1);

// End the run of dispatch cells
objData.EmitZeroPointer();

int interfaceMethodSlot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, _targetMethod);
if (factory.Target.PointerSize == 8)
{
objData.EmitLong(interfaceMethodSlot);
}
else
{
throw new NotImplementedException();
}

return objData.ToObjectData();
}
}
}
Loading

0 comments on commit 811a323

Please sign in to comment.