Skip to content

Commit

Permalink
Work towards shared generics support in IDynamicIntefaceCastable (#1443)
Browse files Browse the repository at this point in the history
This is enough to get all our test to pass.

The rest is tracked in https://github.com/dotnet/runtimelab/issues/1442.

It's a bunch of work and at this point I don't know how much we need it.
  • Loading branch information
MichalStrehovsky authored Aug 24, 2021
1 parent 59a514b commit 3167934
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,12 @@ internal static class SharedCodeHelpers
Debug.Assert(interfaceIndex <= pType->NumInterfaces);
return pType->InterfaceMap[interfaceIndex].InterfaceType;
}

public static unsafe MethodTable* GetCurrentSharedThunkContext()
{
// TODO: We should return the current context from the ThunkPool
// https://github.com/dotnet/runtimelab/issues/1442
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ private static DefaultInterfaceMethodResolution ResolveInterfaceMethodToDefaultI
// If we're asking about an interface, include the interface in the list.
consideredInterfaces = new DefType[currentType.RuntimeInterfaces.Length + 1];
Array.Copy(currentType.RuntimeInterfaces, consideredInterfaces, currentType.RuntimeInterfaces.Length);
consideredInterfaces[consideredInterfaces.Length - 1] = currentType;
consideredInterfaces[consideredInterfaces.Length - 1] = (DefType)currentType.InstantiateAsOpen();
}

foreach (MetadataType runtimeInterface in consideredInterfaces)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ namespace ILCompiler
// Contains functionality related to instantiating thunks for default interface methods
partial class CompilerTypeSystemContext
{
private const int UseContextFromRuntime = -1;

/// <summary>
/// For a shared (canonical) default interface method, gets a method that can be used to call the
/// method on a specific implementing class.
Expand All @@ -76,8 +78,17 @@ public MethodDesc GetDefaultInterfaceMethodImplementationThunk(MethodDesc target
Debug.Assert(interfaceOnDefinition.GetTypeDefinition() == targetMethod.OwningType.GetTypeDefinition());
Debug.Assert(targetMethod.OwningType.IsInterface);

int interfaceIndex = Array.IndexOf(implementingClass.GetTypeDefinition().RuntimeInterfaces, interfaceOnDefinition);
Debug.Assert(interfaceIndex >= 0);
int interfaceIndex;
if (implementingClass.IsInterface)
{
Debug.Assert(((MetadataType)implementingClass).IsDynamicInterfaceCastableImplementation());
interfaceIndex = UseContextFromRuntime;
}
else
{
interfaceIndex = Array.IndexOf(implementingClass.GetTypeDefinition().RuntimeInterfaces, interfaceOnDefinition);
Debug.Assert(interfaceIndex >= 0);
}

// Get a method that will inject the appropriate instantiation context to the
// target default interface method.
Expand Down Expand Up @@ -197,15 +208,23 @@ public override MethodIL EmitIL()

FieldDesc eeTypeField = Context.GetWellKnownType(WellKnownType.Object).GetKnownField("m_pEEType");
MethodDesc getOrdinalInterfaceMethod = Context.GetHelperEntryPoint("SharedCodeHelpers", "GetOrdinalInterface");
MethodDesc getCurrentContext = Context.GetHelperEntryPoint("SharedCodeHelpers", "GetCurrentSharedThunkContext");

// Load "this"
codeStream.EmitLdArg(0);

// Load the instantiating argument.
codeStream.EmitLdArg(0);
codeStream.Emit(ILOpcode.ldfld, emit.NewToken(eeTypeField));
codeStream.EmitLdc(_interfaceIndex);
codeStream.Emit(ILOpcode.call, emit.NewToken(getOrdinalInterfaceMethod));
if (_interfaceIndex == UseContextFromRuntime)
{
codeStream.Emit(ILOpcode.call, emit.NewToken(getCurrentContext));
}
else
{
codeStream.EmitLdArg(0);
codeStream.Emit(ILOpcode.ldfld, emit.NewToken(eeTypeField));
codeStream.EmitLdc(_interfaceIndex);
codeStream.Emit(ILOpcode.call, emit.NewToken(getOrdinalInterfaceMethod));
}

// Load rest of the arguments
for (int i = 0; i < _targetMethod.Signature.Length; i++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,7 @@ public sealed override IEnumerable<CombinedDependencyListEntry> GetConditionalSt
if (resolution == DefaultInterfaceMethodResolution.DefaultImplementation)
{
DefType providingInterfaceDefinitionType = (DefType)implMethod.OwningType;
if (!interfaceType.IsTypeDefinition)
implMethod = implMethod.InstantiateSignature(defType.Instantiation, Instantiation.Empty);
implMethod = implMethod.InstantiateSignature(defType.Instantiation, Instantiation.Empty);

MethodDesc defaultIntfMethod = implMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
if (defaultIntfMethod.IsCanonicalMethod(CanonicalFormKind.Any))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,7 @@ void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory)
if (result == DefaultInterfaceMethodResolution.DefaultImplementation)
{
DefType providingInterfaceDefinitionType = (DefType)implMethod.OwningType;
if (interfaceType != interfaceDefinitionType)
implMethod = implMethod.InstantiateSignature(declType.Instantiation, Instantiation.Empty);

implMethod = implMethod.InstantiateSignature(declType.Instantiation, Instantiation.Empty);
implSlot = VirtualMethodSlotHelper.GetDefaultInterfaceMethodSlot(factory, implMethod, declType, providingInterfaceDefinitionType);
}
else if (result == DefaultInterfaceMethodResolution.Reabstraction)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,7 @@ public bool BuildSealedVTableSlots(NodeFactory factory, bool relocsOnly)
if (resolution == DefaultInterfaceMethodResolution.DefaultImplementation)
{
DefType providingInterfaceDefinitionType = (DefType)implMethod.OwningType;
if (interfaceType != interfaceDefinitionType)
implMethod = implMethod.InstantiateSignature(declType.Instantiation, Instantiation.Empty);

implMethod = implMethod.InstantiateSignature(declType.Instantiation, Instantiation.Empty);
_sealedVTableEntries.Add(SealedVTableEntry.FromDefaultInterfaceMethod(implMethod, providingInterfaceDefinitionType));
}
}
Expand Down
3 changes: 0 additions & 3 deletions src/tests/issues.targets
Original file line number Diff line number Diff line change
Expand Up @@ -998,9 +998,6 @@
<ExcludeList Include="$(XunitTestBinBase)/Interop/ICustomMarshaler/Primitives/ICustomMarshaler_TargetWindows/*">
<Issue>https://github.com/dotnet/runtimelab/issues/160</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Interop/IDynamicInterfaceCastable/IDynamicInterfaceCastable/*">
<Issue>https://github.com/dotnet/runtimelab/issues/162</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Interop/IJW/**/*">
<Issue>https://github.com/dotnet/runtimelab/issues/155: C++/CLI</Issue>
</ExcludeList>
Expand Down
12 changes: 12 additions & 0 deletions src/tests/nativeaot/SmokeTests/Interfaces/Interfaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,12 @@ interface IInterfaceCastableImpl : IInterface
string IInterface.GetCookie() => "IInterfaceCastableImpl";
}

[DynamicInterfaceCastableImplementation]
interface IInterfaceCastableImpl<T> : IInterface
{
string IInterface.GetCookie() => typeof(T).Name;
}

interface IInterfaceImpl : IInterface
{
string IInterface.GetCookie() => "IInterfaceImpl";
Expand Down Expand Up @@ -794,6 +800,12 @@ public static void Run()
if (o.GetCookie() != "IInterfaceImpl")
throw new Exception();
}

{
IInterface o = (IInterface)new CastableClass<IInterface, IInterfaceCastableImpl<int>>();
if (o.GetCookie() != "Int32")
throw new Exception();
}
}
}
}

0 comments on commit 3167934

Please sign in to comment.