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

Commit

Permalink
Implement GetInterfaceMap
Browse files Browse the repository at this point in the history
  • Loading branch information
Suchiman committed May 19, 2020
1 parent a4b2755 commit 7a17a57
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public bool IsOpenNonVirtualResolve
{
get
{
switch(_resolveType)
switch (_resolveType)
{
case OpenNonVirtualResolve:
case OpenNonVirtualResolveLookthruUnboxing:
Expand Down Expand Up @@ -174,6 +174,16 @@ unsafe public static IntPtr ResolveMethod(IntPtr resolver, object thisObject)
return TypeLoaderExports.OpenInstanceMethodLookup(resolver, thisObject);
}

unsafe public static IntPtr ResolveMethod(IntPtr resolverPtr, RuntimeTypeHandle thisType)
{
OpenMethodResolver* resolver = ((OpenMethodResolver*)resolverPtr);
IntPtr nonVirtualOpenInvokeCodePointer = resolver->_nonVirtualOpenInvokeCodePointer;
if (nonVirtualOpenInvokeCodePointer != IntPtr.Zero)
return nonVirtualOpenInvokeCodePointer;

return RuntimeImports.RhResolveDispatchOnType(thisType.ToEETypePtr(), resolver->_declaringType, checked((ushort)resolver->_methodHandleOrSlotOrCodePointer.ToInt32()));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int _rotl(int value, int shift)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

using OpenMethodInvoker = System.Reflection.Runtime.MethodInfos.OpenMethodInvoker;
using EnumInfo = Internal.Runtime.Augments.EnumInfo;
using System.Reflection.Runtime.MethodInfos;

namespace Internal.Reflection.Core.Execution
{
Expand Down Expand Up @@ -41,6 +42,8 @@ public abstract class ExecutionEnvironment
public abstract bool IsAssignableFrom(RuntimeTypeHandle dstType, RuntimeTypeHandle srcType);
public abstract bool TryGetBaseType(RuntimeTypeHandle typeHandle, out RuntimeTypeHandle baseTypeHandle);
public abstract IEnumerable<RuntimeTypeHandle> TryGetImplementedInterfaces(RuntimeTypeHandle typeHandle);
public abstract void VerifyInterfaceIsImplemented(RuntimeTypeHandle typeHandle, RuntimeTypeHandle ifaceHandle);
public abstract void GetInterfaceMap(Type instanceType, Type interfaceType, out MethodInfo[] interfaceMethods, out MethodInfo[] targetMethods);
public abstract bool IsReflectionBlocked(RuntimeTypeHandle typeHandle);
public abstract string GetLastResortString(RuntimeTypeHandle typeHandle);

Expand Down Expand Up @@ -120,5 +123,10 @@ internal MethodInvoker GetMethodInvoker(RuntimeTypeInfo declaringType, QMethodDe
throw ReflectionCoreExecution.ExecutionDomain.CreateNonInvokabilityException(exceptionPertainant);
return methodInvoker;
}

protected MethodInvoker GetMethodInvoker(MethodInfo methodInfo)
{
return ((RuntimeMethodInfo)methodInfo).MethodInvoker;
}
}
}
7 changes: 3 additions & 4 deletions src/System.Private.Reflection.Core/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,6 @@
<data name="Arg_AmbiguousMatchException" xml:space="preserve">
<value>Ambiguous match found.</value>
</data>
<data name="PlatformNotSupported_InterfaceMap" xml:space="preserve">
<value>GetRuntimeInterfaceMap() is not supported on this runtime.</value>
</data>
<data name="NoMetadataTokenAvailable" xml:space="preserve">
<value>There is no metadata token available for the given member.</value>
</data>
Expand Down Expand Up @@ -261,7 +258,6 @@
<data name="Acc_CreateVoid" xml:space="preserve">
<value>Cannot dynamically create an instance of System.Void.</value>
</data>

<data name="Arg_GenericParameter" xml:space="preserve">
<value>Method must be called on a Type for which Type.IsGenericParameter is false.</value>
</data>
Expand Down Expand Up @@ -364,4 +360,7 @@
<data name="InvalidOperation_NoValue" xml:space="preserve">
<value>Nullable object must have a value.</value>
</data>
<data name="Argument_ArrayGetInterfaceMap" xml:space="preserve">
<value>Interface maps for generic interfaces on arrays cannot be retrieved.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public sealed override Type BaseType
public abstract override bool ContainsGenericParameters { get; }

public abstract override IEnumerable<CustomAttributeData> CustomAttributes { get; }

//
// Left unsealed as generic parameter types must override.
//
Expand Down Expand Up @@ -194,7 +194,35 @@ public sealed override MemberInfo[] GetDefaultMembers()

public sealed override InterfaceMapping GetInterfaceMap(Type interfaceType)
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_InterfaceMap);
if (IsGenericParameter)
throw new InvalidOperationException(SR.Arg_GenericParameter);

if (interfaceType is null)
throw new ArgumentNullException(nameof(interfaceType));

if (!(interfaceType is RuntimeTypeInfo))
throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(interfaceType));

RuntimeTypeHandle interfaceTypeHandle = interfaceType.TypeHandle;

ReflectionCoreExecution.ExecutionEnvironment.VerifyInterfaceIsImplemented(TypeHandle, interfaceTypeHandle);
Debug.Assert(interfaceType.IsInterface);
Debug.Assert(!IsInterface);

// SZArrays implement the methods on IList`1, IEnumerable`1, and ICollection`1 with
// runtime magic. We don't have accurate interface maps for them.
if (IsSZArray && interfaceType.IsGenericType)
throw new ArgumentException(SR.Argument_ArrayGetInterfaceMap);

ReflectionCoreExecution.ExecutionEnvironment.GetInterfaceMap(this, interfaceType, out MethodInfo[] interfaceMethods, out MethodInfo[] targetMethods);

InterfaceMapping im;
im.InterfaceType = interfaceType;
im.TargetType = this;
im.InterfaceMethods = interfaceMethods;
im.TargetMethods = targetMethods;

return im;
}

//
Expand All @@ -210,7 +238,7 @@ public override Guid GUID
}

public abstract override bool HasSameMetadataDefinitionAs(MemberInfo other);

public sealed override IEnumerable<Type> ImplementedInterfaces
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Runtime.General;

using Internal.Runtime.Augments;

using Internal.Reflection.Core.Execution;
using Internal.Reflection.Execution.FieldAccessors;
using Internal.Reflection.Execution.MethodInvokers;

namespace Internal.Reflection.Execution
{
Expand Down Expand Up @@ -57,6 +59,62 @@ public sealed override IEnumerable<RuntimeTypeHandle> TryGetImplementedInterface
return RuntimeAugments.TryGetImplementedInterfaces(typeHandle);
}

public sealed override void VerifyInterfaceIsImplemented(RuntimeTypeHandle typeHandle, RuntimeTypeHandle ifaceHandle)
{
if (RuntimeAugments.IsInterface(typeHandle))
{
throw new ArgumentException(SR.Argument_InterfaceMap);
}

if (!RuntimeAugments.IsInterface(ifaceHandle))
{
throw new ArgumentException(SR.Arg_MustBeInterface);
}

if (RuntimeAugments.IsAssignableFrom(ifaceHandle, typeHandle))
{
return;
}

throw new ArgumentException(SR.Arg_NotFoundIFace);
}

public sealed override void GetInterfaceMap(Type instanceType, Type interfaceType, out MethodInfo[] interfaceMethods, out MethodInfo[] targetMethods)
{
MethodInfo[] ifaceMethods = interfaceType.GetMethods();
var tMethods = new MethodInfo[ifaceMethods.Length];
for (int i = 0; i < ifaceMethods.Length; i++)
{
var invoker = (VirtualMethodInvoker)GetMethodInvoker(ifaceMethods[i]);

IntPtr classRtMethodHandle = invoker.ResolveTarget(instanceType.TypeHandle);
if (classRtMethodHandle == IntPtr.Zero)
{
goto notFound;
}

MethodBase methodBase = RuntimeAugments.Callbacks.GetMethodBaseFromStartAddressIfAvailable(classRtMethodHandle);
if (methodBase == null)
{
goto notFound;
}

tMethods[i] = (MethodInfo)methodBase;
continue;

notFound:
if (instanceType.IsAbstract)
{
throw new PlatformNotSupportedException(SR.Format(SR.Arg_InterfaceMapMustNotBeAbstract, interfaceType.FullName, instanceType.FullName));
}

throw new NotSupportedException();
}

interfaceMethods = ifaceMethods;
targetMethods = tMethods;
}

public sealed override string GetLastResortString(RuntimeTypeHandle typeHandle)
{
return RuntimeAugments.GetLastResortString(typeHandle);
Expand All @@ -67,7 +125,7 @@ public sealed override string GetLastResortString(RuntimeTypeHandle typeHandle)
//==============================================================================================
public sealed override FieldAccessor CreateLiteralFieldAccessor(object value, RuntimeTypeHandle fieldTypeHandle)
{
return new LiteralFieldAccessor(value, fieldTypeHandle);
return new LiteralFieldAccessor(value, fieldTypeHandle);
}

public sealed override EnumInfo GetEnumInfo(RuntimeTypeHandle typeHandle)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ protected sealed override Object Invoke(Object thisObject, Object[] arguments, B
return result;
}

internal IntPtr ResolveTarget(RuntimeTypeHandle type)
{
return OpenMethodResolver.ResolveMethod(MethodInvokeInfo.VirtualResolveData, type);
}

// On CoreCLR/Desktop, we do not attempt to resolve the target virtual method based on the type of the 'this' pointer.
// For compatibility reasons, we'll do the same here.
public sealed override IntPtr LdFtnResult
Expand Down
12 changes: 12 additions & 0 deletions src/System.Private.Reflection.Execution/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,16 @@
<data name="DelegateGetMethodInfo_ObjectArrayDelegate" xml:space="preserve">
<value>Cannot retrieve a MethodInfo for this delegate because the delegate target is an interpreted LINQ expression.</value>
</data>
<data name="Argument_InterfaceMap" xml:space="preserve">
<value>'this' type cannot be an interface itself.</value>
</data>
<data name="Arg_MustBeInterface" xml:space="preserve">
<value>Type passed must be an interface.</value>
</data>
<data name="Arg_NotFoundIFace" xml:space="preserve">
<value>Interface not found.</value>
</data>
<data name="Arg_InterfaceMapMustNotBeAbstract" xml:space="preserve">
<value>Could not retrieve the mapping of the interface '{0}' on type '{1}' because the type implements the interface abstractly.</value>
</data>
</root>

0 comments on commit 7a17a57

Please sign in to comment.