Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert ReflectionInvocation.CanValueSpecialCast() to managed #108305

Merged
23 changes: 22 additions & 1 deletion src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,28 @@ internal RuntimeType GetRuntimeType()
}

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern CorElementType GetCorElementType(RuntimeType type);
private static extern CorElementType GetCorElementTypeInternal(RuntimeType type);

internal static CorElementType GetCorElementType(RuntimeType type)
{
if (type is null)
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
throw new ArgumentNullException(SR.Arg_InvalidHandle);
}
return GetCorElementTypeInternal(type);
}

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern CorElementType GetVerifierCorElementTypeInternal(RuntimeType type);

internal static CorElementType GetVerifierCorElementType(RuntimeType type)
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
if (type is null)
{
throw new ArgumentNullException(SR.Arg_InvalidHandle);
}
return GetVerifierCorElementTypeInternal(type);
}

internal static RuntimeAssembly GetAssembly(RuntimeType type)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3677,13 +3677,48 @@ public override Type MakeArrayType(int rank)
#region Invoke Member

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern bool CanValueSpecialCast(RuntimeType valueType, RuntimeType targetType);
private static extern bool CanPrimitiveWiden(CorElementType valueType, CorElementType targetType);
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved

private static bool CanValueSpecialCast(RuntimeType valueType, RuntimeType targetType)
{
Debug.Assert(targetType.IsPointer || targetType.IsEnum || targetType.IsPrimitive || targetType.IsFunctionPointer);

CorElementType targetCorElement = RuntimeTypeHandle.GetVerifierCorElementType(targetType);
if (targetCorElement is CorElementType.ELEMENT_TYPE_PTR or CorElementType.ELEMENT_TYPE_FNPTR)
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
// The object must be an IntPtr or a System.Reflection.Pointer
if (valueType == typeof(IntPtr))
{
// It's an IntPtr, it's good.
return true;
}

// void* assigns to any pointer
if (IsVoidPtr(targetType))
{
return true;
}

// otherwise the type of the pointer must match.
return valueType.IsAssignableTo(targetType);
}
else
{
// The type is an enum or a primitive. To have any chance of assignment
// the object type must be an enum or primitive as well.
// So get the internal cor element and that must be the same or widen.
CorElementType valueCorElement = RuntimeTypeHandle.GetVerifierCorElementType(valueType);
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
return CanPrimitiveWiden(valueCorElement, targetCorElement);
}

static bool IsVoidPtr(RuntimeType type)
=> type.IsPointer && type.GetElementType() == typeof(void);
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
}

private CheckValueStatus TryChangeTypeSpecial(ref object value)
{
Pointer? pointer = value as Pointer;
RuntimeType srcType = pointer != null ? pointer.GetPointerType() : (RuntimeType)value.GetType();

if (!CanValueSpecialCast(srcType, this))
{
return CheckValueStatus.ArgumentException;
Expand Down
5 changes: 3 additions & 2 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ FCFuncEnd()

FCFuncStart(gSystem_RuntimeType)
FCFuncElement("GetGUID", ReflectionInvocation::GetGUID)
FCFuncElement("CanValueSpecialCast", ReflectionInvocation::CanValueSpecialCast)
FCFuncElement("CanPrimitiveWiden", ReflectionInvocation::CanPrimitiveWiden)
#if defined(FEATURE_COMINTEROP)
FCFuncElement("InvokeDispMethod", ReflectionInvocation::InvokeDispMethod)
#endif // defined(FEATURE_COMINTEROP)
Expand All @@ -108,7 +108,8 @@ FCFuncStart(gCOMTypeHandleFuncs)
FCFuncElement("GetDeclaringType", RuntimeTypeHandle::GetDeclaringType)
FCFuncElement("GetFirstIntroducedMethod", RuntimeTypeHandle::GetFirstIntroducedMethod)
FCFuncElement("GetNextIntroducedMethod", RuntimeTypeHandle::GetNextIntroducedMethod)
FCFuncElement("GetCorElementType", RuntimeTypeHandle::GetCorElementType)
FCFuncElement("GetCorElementTypeInternal", RuntimeTypeHandle::GetCorElementTypeInternal)
FCFuncElement("GetVerifierCorElementTypeInternal", RuntimeTypeHandle::GetVerifierCorElementTypeInternal)
FCFuncElement("GetAssemblyIfExists", RuntimeTypeHandle::GetAssemblyIfExists)
FCFuncElement("GetModuleIfExists", RuntimeTypeHandle::GetModuleIfExists)
FCFuncElement("GetBaseType", RuntimeTypeHandle::GetBaseType)
Expand Down
54 changes: 8 additions & 46 deletions src/coreclr/vm/reflectioninvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,53 +62,15 @@ FCIMPL5(Object*, RuntimeFieldHandle::GetValue, ReflectFieldObject *pFieldUNSAFE,
}
FCIMPLEND

FCIMPL2(FC_BOOL_RET, ReflectionInvocation::CanValueSpecialCast, ReflectClassBaseObject *pValueTypeUNSAFE, ReflectClassBaseObject *pTargetTypeUNSAFE) {
CONTRACTL
{
FCALL_CHECK;
PRECONDITION(CheckPointer(pValueTypeUNSAFE));
PRECONDITION(CheckPointer(pTargetTypeUNSAFE));
}
CONTRACTL_END;

REFLECTCLASSBASEREF refValueType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pValueTypeUNSAFE);
REFLECTCLASSBASEREF refTargetType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTargetTypeUNSAFE);

TypeHandle valueType = refValueType->GetType();
TypeHandle targetType = refTargetType->GetType();

// we are here only if the target type is a primitive, an enum or a pointer

CorElementType targetCorElement = targetType.GetVerifierCorElementType();

BOOL ret = TRUE;
HELPER_METHOD_FRAME_BEGIN_RET_2(refValueType, refTargetType);
// the field type is a pointer
if (targetCorElement == ELEMENT_TYPE_PTR || targetCorElement == ELEMENT_TYPE_FNPTR) {
// the object must be an IntPtr or a System.Reflection.Pointer
if (valueType == TypeHandle(CoreLibBinder::GetClass(CLASS__INTPTR))) {
//
// it's an IntPtr, it's good.
}
//
// it's a System.Reflection.Pointer object
FCIMPL2(FC_BOOL_RET, ReflectionInvocation::CanPrimitiveWiden, CorElementType valueCorElement, CorElementType targetCorElement)
{
FCALL_CONTRACT;

// void* assigns to any pointer. Otherwise the type of the pointer must match
else if (!InvokeUtil::IsVoidPtr(targetType)) {
if (!valueType.CanCastTo(targetType))
ret = FALSE;
}
} else {
// the field type is an enum or a primitive. To have any chance of assignement the object type must
// be an enum or primitive as well.
// So get the internal cor element and that must be the same or widen
CorElementType valueCorElement = valueType.GetVerifierCorElementType();
if (InvokeUtil::IsPrimitiveType(valueCorElement))
ret = (InvokeUtil::CanPrimitiveWiden(targetCorElement, valueCorElement)) ? TRUE : FALSE;
else
ret = FALSE;
}
HELPER_METHOD_FRAME_END();
// We are here only if the target type is a primitive, an enum or a pointer
_ASSERTE(targetCorElement != ELEMENT_TYPE_PTR && targetCorElement != ELEMENT_TYPE_FNPTR);
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
BOOL ret = (InvokeUtil::IsPrimitiveType(valueCorElement) && InvokeUtil::CanPrimitiveWiden(targetCorElement, valueCorElement))
? TRUE
: FALSE;
FC_RETURN_BOOL(ret);
}
FCIMPLEND
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/reflectioninvocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class ReflectionInvocation {
static FCDECL2(void, GetGUID, ReflectClassBaseObject* refThisUNSAFE, GUID * result);

// helper fcalls for invocation
static FCDECL2(FC_BOOL_RET, CanValueSpecialCast, ReflectClassBaseObject *valueType, ReflectClassBaseObject *targetType);
static FCDECL2(FC_BOOL_RET, CanPrimitiveWiden, CorElementType valueCorElement, CorElementType targetCorElement);
};

extern "C" void QCALLTYPE ReflectionInvocation_CompileMethod(MethodDesc * pMD);
Expand Down
23 changes: 17 additions & 6 deletions src/coreclr/vm/runtimehandles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,18 +246,29 @@ FCIMPL1(void, RuntimeTypeHandle::GetNextIntroducedMethod, MethodDesc ** ppMethod
FCIMPLEND
#include <optdefault.h>

FCIMPL1(INT32, RuntimeTypeHandle::GetCorElementType, ReflectClassBaseObject *pTypeUNSAFE) {
CONTRACTL {
FCIMPL1(INT32, RuntimeTypeHandle::GetCorElementTypeInternal, ReflectClassBaseObject *pTypeUNSAFE)
{
CONTRACTL
{
FCALL_CHECK;
PRECONDITION(pTypeUNSAFE != NULL);
}
CONTRACTL_END;

REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
return ((REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE))->GetType().GetSignatureCorElementType();
}
FCIMPLEND

if (refType == NULL)
FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
FCIMPL1(INT32, RuntimeTypeHandle::GetVerifierCorElementTypeInternal, ReflectClassBaseObject *pTypeUNSAFE)
{
CONTRACTL
{
FCALL_CHECK;
PRECONDITION(pTypeUNSAFE != NULL);
}
CONTRACTL_END;

return refType->GetType().GetSignatureCorElementType();
return ((REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE))->GetType().GetVerifierCorElementType();
}
FCIMPLEND

Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/vm/runtimehandles.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ class RuntimeTypeHandle {

static FCDECL1(PtrArray*, GetInterfaces, ReflectClassBaseObject *pType);

static FCDECL1(INT32, GetCorElementType, PTR_ReflectClassBaseObject pType);
static FCDECL1(INT32, GetCorElementTypeInternal, PTR_ReflectClassBaseObject pType);
static FCDECL1(INT32, GetVerifierCorElementTypeInternal, PTR_ReflectClassBaseObject pType);
static FCDECL1(ReflectClassBaseObject*, GetElementType, ReflectClassBaseObject* pType);
static FCDECL1(INT32, GetNumVirtuals, ReflectClassBaseObject *pType);
static FCDECL2(MethodDesc*, GetMethodAt, PTR_ReflectClassBaseObject pType, INT32 slot);
Expand Down
Loading