Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,11 @@ public static object CheckArgument(object srcObject, RuntimeTypeHandle dstType,
return InvokeUtils.CheckArgument(srcObject, dstType.ToMethodTable(), InvokeUtils.CheckArgumentSemantics.DynamicInvoke, binderBundle);
}

public static object CheckArgument(object srcObject, RuntimeTypeHandle dstType, BinderBundle? binderBundle, out bool copyBack)
{
return InvokeUtils.CheckArgument(srcObject, dstType.ToMethodTable(), InvokeUtils.CheckArgumentSemantics.DynamicInvoke, binderBundle, out copyBack);
}

// FieldInfo.SetValueDirect() has a completely different set of rules on how to coerce the argument from
// the other Reflection api.
public static object CheckArgumentForDirectFieldAccess(object srcObject, RuntimeTypeHandle dstType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ internal enum CheckArgumentSemantics

internal static object? CheckArgument(object? srcObject, MethodTable* dstEEType, CheckArgumentSemantics semantics, BinderBundle? binderBundle)
{
return CheckArgument(srcObject, dstEEType, semantics, binderBundle, out _);
}

internal static object? CheckArgument(object? srcObject, MethodTable* dstEEType, CheckArgumentSemantics semantics, BinderBundle? binderBundle, out bool copyBack)
{
copyBack = false;

// Methods with ByRefLike types in signatures should be filtered out earlier
Debug.Assert(!dstEEType->IsByRefLike);

Expand All @@ -65,23 +72,24 @@ internal enum CheckArgumentSemantics
}
else
{
MethodTable* srcEEType = srcObject.GetMethodTable();

if (srcEEType == dstEEType ||
RuntimeImports.AreTypesAssignable(srcEEType, dstEEType) ||
(dstEEType->IsInterface && srcObject is Runtime.InteropServices.IDynamicInterfaceCastable castable
&& castable.IsInterfaceImplemented(new RuntimeTypeHandle(dstEEType), throwIfNotImplemented: false)))
if (IsArgumentAssignable(srcObject, dstEEType))
{
return srcObject;
}

return CheckArgumentConversions(srcObject, dstEEType, semantics, binderBundle);
return CheckArgumentConversions(srcObject, dstEEType, semantics, binderBundle, out copyBack);
}
}

internal static object? CheckArgumentConversions(object srcObject, MethodTable* dstEEType, CheckArgumentSemantics semantics, BinderBundle? binderBundle)
{
return CheckArgumentConversions(srcObject, dstEEType, semantics, binderBundle, out _);
}

internal static object? CheckArgumentConversions(object srcObject, MethodTable* dstEEType, CheckArgumentSemantics semantics, BinderBundle? binderBundle, out bool copyBack)
{
object? dstObject;
copyBack = false;
Exception exception = ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(srcObject, dstEEType, semantics, out dstObject);
if (exception == null)
return dstObject;
Expand All @@ -93,11 +101,21 @@ internal enum CheckArgumentSemantics
Type exactDstType = Type.GetTypeFromHandle(new RuntimeTypeHandle(dstEEType))!;

srcObject = binderBundle.ChangeType(srcObject, exactDstType);
copyBack = srcObject is not null && IsArgumentAssignable(srcObject, dstEEType);

// For compat with desktop, the result of the binder call gets processed through the default rules again.
return CheckArgument(srcObject, dstEEType, semantics, binderBundle: null);
}

private static bool IsArgumentAssignable(object srcObject, MethodTable* dstEEType)
{
MethodTable* srcEEType = srcObject.GetMethodTable();
return srcEEType == dstEEType ||
RuntimeImports.AreTypesAssignable(srcEEType, dstEEType) ||
(dstEEType->IsInterface && srcObject is Runtime.InteropServices.IDynamicInterfaceCastable castable
&& castable.IsInterfaceImplemented(new RuntimeTypeHandle(dstEEType), throwIfNotImplemented: false));
}

// Special coersion rules for primitives, enums and pointer.
private static Exception ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(object srcObject, MethodTable* dstEEType, CheckArgumentSemantics semantics, out object? dstObject)
{
Expand Down
Loading
Loading