diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs index e8804e16b76f62..323835bc9526d6 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs @@ -11,7 +11,6 @@ ===========================================================*/ using System.Diagnostics; -using System.Runtime; using System.Runtime.InteropServices; using CorElementType = System.Reflection.CorElementType; @@ -85,13 +84,5 @@ private EETypeElementType ElementType return _value->ElementType; } } - - internal RuntimeImports.RhCorElementTypeInfo CorElementTypeInfo - { - get - { - return RuntimeImports.GetRhCorElementTypeInfo(CorElementType); - } - } } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs index bc61b34c3b3027..f8825dbfc91468 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using MethodTable = Internal.Runtime.MethodTable; +using EETypeElementType = Internal.Runtime.EETypeElementType; namespace System { @@ -126,65 +127,65 @@ private static Exception ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(obje return CreateChangeTypeException(srcEEType, dstEEType, semantics); } - CorElementType dstCorElementType = new EETypePtr(dstEEType).CorElementType; - if (!new EETypePtr(srcEEType).CorElementTypeInfo.CanWidenTo(dstCorElementType)) + EETypeElementType dstElementType = dstEEType->ElementType; + if (!CanPrimitiveWiden(dstElementType, srcEEType->ElementType)) { dstObject = null; return CreateChangeTypeArgumentException(srcEEType, dstEEType); } - switch (dstCorElementType) + switch (dstElementType) { - case CorElementType.ELEMENT_TYPE_BOOLEAN: + case EETypeElementType.Boolean: dstObject = Convert.ToBoolean(srcObject); break; - case CorElementType.ELEMENT_TYPE_CHAR: + case EETypeElementType.Char: char charValue = Convert.ToChar(srcObject); dstObject = dstEEType->IsEnum ? Enum.ToObject(dstEEType, charValue) : charValue; break; - case CorElementType.ELEMENT_TYPE_I1: + case EETypeElementType.SByte: sbyte sbyteValue = Convert.ToSByte(srcObject); dstObject = dstEEType->IsEnum ? Enum.ToObject(dstEEType, sbyteValue) : sbyteValue; break; - case CorElementType.ELEMENT_TYPE_I2: + case EETypeElementType.Int16: short shortValue = Convert.ToInt16(srcObject); dstObject = dstEEType->IsEnum ? Enum.ToObject(dstEEType, shortValue) : shortValue; break; - case CorElementType.ELEMENT_TYPE_I4: + case EETypeElementType.Int32: int intValue = Convert.ToInt32(srcObject); dstObject = dstEEType->IsEnum ? Enum.ToObject(dstEEType, intValue) : intValue; break; - case CorElementType.ELEMENT_TYPE_I8: + case EETypeElementType.Int64: long longValue = Convert.ToInt64(srcObject); dstObject = dstEEType->IsEnum ? Enum.ToObject(dstEEType, longValue) : longValue; break; - case CorElementType.ELEMENT_TYPE_U1: + case EETypeElementType.Byte: byte byteValue = Convert.ToByte(srcObject); dstObject = dstEEType->IsEnum ? Enum.ToObject(dstEEType, byteValue) : byteValue; break; - case CorElementType.ELEMENT_TYPE_U2: + case EETypeElementType.UInt16: ushort ushortValue = Convert.ToUInt16(srcObject); dstObject = dstEEType->IsEnum ? Enum.ToObject(dstEEType, ushortValue) : ushortValue; break; - case CorElementType.ELEMENT_TYPE_U4: + case EETypeElementType.UInt32: uint uintValue = Convert.ToUInt32(srcObject); dstObject = dstEEType->IsEnum ? Enum.ToObject(dstEEType, uintValue) : uintValue; break; - case CorElementType.ELEMENT_TYPE_U8: + case EETypeElementType.UInt64: ulong ulongValue = Convert.ToUInt64(srcObject); dstObject = dstEEType->IsEnum ? Enum.ToObject(dstEEType, (long)ulongValue) : ulongValue; break; - case CorElementType.ELEMENT_TYPE_R4: + case EETypeElementType.Single: if (new EETypePtr(srcEEType).CorElementType == CorElementType.ELEMENT_TYPE_CHAR) { dstObject = (float)(char)srcObject; @@ -195,7 +196,7 @@ private static Exception ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(obje } break; - case CorElementType.ELEMENT_TYPE_R8: + case EETypeElementType.Double: if (new EETypePtr(srcEEType).CorElementType == CorElementType.ELEMENT_TYPE_CHAR) { dstObject = (double)(char)srcObject; @@ -207,7 +208,7 @@ private static Exception ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(obje break; default: - Debug.Fail("Unexpected CorElementType: " + dstCorElementType + ": Not a valid widening target."); + Debug.Fail("Unexpected CorElementType: " + dstElementType + ": Not a valid widening target."); dstObject = null; return CreateChangeTypeException(srcEEType, dstEEType, semantics); } @@ -216,6 +217,34 @@ private static Exception ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(obje return null; } + private static bool CanPrimitiveWiden(EETypeElementType destType, EETypeElementType srcType) + { + Debug.Assert(destType is < EETypeElementType.ValueType and >= EETypeElementType.Boolean); + Debug.Assert(srcType is < EETypeElementType.ValueType and >= EETypeElementType.Boolean); + + ReadOnlySpan primitiveAttributes = [ + 0x0000, // Unknown + 0x0000, // Void + 0x0004, // Boolean (W = BOOL) + 0xCf88, // Char (W = U2, CHAR, I4, U4, I8, U8, R4, R8) + 0xC550, // SByte (W = I1, I2, I4, I8, R4, R8) + 0xCFE8, // Byte (W = CHAR, U1, I2, U2, I4, U4, I8, U8, R4, R8) + 0xC540, // Int16 (W = I2, I4, I8, R4, R8) + 0xCF88, // UInt16 (W = U2, CHAR, I4, U4, I8, U8, R4, R8) + 0xC500, // Int32 (W = I4, I8, R4, R8) + 0xCE00, // UInt32 (W = U4, I8, R4, R8) + 0xC400, // Int64 (W = I8, R4, R8) + 0xC800, // UInt64 (W = U8, R4, R8) + 0x0000, // IntPtr + 0x0000, // UIntPtr + 0xC000, // Single (W = R4, R8) + 0x8000, // Double (W = R8) + ]; + + ushort mask = (ushort)(1 << (byte)destType); + return (primitiveAttributes[(int)srcType & 0xF] & mask) != 0; + } + private static Exception ConvertPointerIfPossible(object srcObject, MethodTable* dstEEType, CheckArgumentSemantics semantics, out object dstPtr) { if (srcObject is IntPtr or UIntPtr) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index 5f1211b5059fc3..3f30983a74c3b2 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -1106,119 +1106,5 @@ internal static partial void NativeRuntimeEventSource_LogWaitHandleWaitStart( [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] internal static unsafe partial void RhCpuIdEx(int* cpuInfo, int functionId, int subFunctionId); #endif - - internal static RhCorElementTypeInfo GetRhCorElementTypeInfo(CorElementType elementType) - { - return RhCorElementTypeInfo.GetRhCorElementTypeInfo(elementType); - } - - internal struct RhCorElementTypeInfo - { - public bool IsPrimitive - { - get - { - return 0 != (_flags & RhCorElementTypeInfoFlags.IsPrimitive); - } - } - - // - // This is a port of InvokeUtil::CanPrimitiveWiden() in the desktop runtime. This is used by various apis such as Array.SetValue() - // and Delegate.DynamicInvoke() which allow value-preserving widenings from one primitive type to another. - // - public bool CanWidenTo(CorElementType targetElementType) - { - // Caller expected to ensure that both sides are primitive before calling us. - Debug.Assert(this.IsPrimitive); - Debug.Assert(GetRhCorElementTypeInfo(targetElementType).IsPrimitive); - - // Once we've asserted that the target is a primitive, we can also assert that it is >= ET_BOOLEAN. - Debug.Assert(targetElementType >= CorElementType.ELEMENT_TYPE_BOOLEAN); - byte targetElementTypeAsByte = (byte)targetElementType; - ushort mask = (ushort)(1 << targetElementTypeAsByte); // This is expected to overflow on larger ET_I and ET_U - this is ok and anticipated. - if (0 != (_widenMask & mask)) - return true; - return false; - } - - internal static RhCorElementTypeInfo GetRhCorElementTypeInfo(CorElementType elementType) - { - // The _lookupTable array only covers a subset of RhCorElementTypes, so we return a default - // info when someone asks for an elementType which does not have an entry in the table. - if ((int)elementType > s_lookupTable.Length) - return default(RhCorElementTypeInfo); - - return s_lookupTable[(int)elementType]; - } - - - private RhCorElementTypeInfoFlags _flags; - - [Flags] - private enum RhCorElementTypeInfoFlags : byte - { - IsValid = 0x01, // Set for all valid CorElementTypeInfo's - IsPrimitive = 0x02, // Is it a primitive type (as defined by TypeInfo.IsPrimitive) - IsFloat = 0x04, // Is it a floating point type - } - - private ushort _widenMask; - - private static RhCorElementTypeInfo[] s_lookupTable = new RhCorElementTypeInfo[] - { - // index = 0x0 - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0x1 - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0x2 = ELEMENT_TYPE_BOOLEAN (W = BOOL) - new RhCorElementTypeInfo { _widenMask = 0x0004, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - // index = 0x3 = ELEMENT_TYPE_CHAR (W = U2, CHAR, I4, U4, I8, U8, R4, R8) (U2 == Char) - new RhCorElementTypeInfo { _widenMask = 0x3f88, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - // index = 0x4 = ELEMENT_TYPE_I1 (W = I1, I2, I4, I8, R4, R8) - new RhCorElementTypeInfo { _widenMask = 0x3550, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - // index = 0x5 = ELEMENT_TYPE_U1 (W = CHAR, U1, I2, U2, I4, U4, I8, U8, R4, R8) - new RhCorElementTypeInfo { _widenMask = 0x3FE8, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - // index = 0x6 = ELEMENT_TYPE_I2 (W = I2, I4, I8, R4, R8) - new RhCorElementTypeInfo { _widenMask = 0x3540, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - // index = 0x7 = ELEMENT_TYPE_U2 (W = U2, CHAR, I4, U4, I8, U8, R4, R8) - new RhCorElementTypeInfo { _widenMask = 0x3F88, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - // index = 0x8 = ELEMENT_TYPE_I4 (W = I4, I8, R4, R8) - new RhCorElementTypeInfo { _widenMask = 0x3500, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - // index = 0x9 = ELEMENT_TYPE_U4 (W = U4, I8, R4, R8) - new RhCorElementTypeInfo { _widenMask = 0x3E00, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - // index = 0xa = ELEMENT_TYPE_I8 (W = I8, R4, R8) - new RhCorElementTypeInfo { _widenMask = 0x3400, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - // index = 0xb = ELEMENT_TYPE_U8 (W = U8, R4, R8) - new RhCorElementTypeInfo { _widenMask = 0x3800, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - // index = 0xc = ELEMENT_TYPE_R4 (W = R4, R8) - new RhCorElementTypeInfo { _widenMask = 0x3000, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive|RhCorElementTypeInfoFlags.IsFloat }, - // index = 0xd = ELEMENT_TYPE_R8 (W = R8) - new RhCorElementTypeInfo { _widenMask = 0x2000, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive|RhCorElementTypeInfoFlags.IsFloat }, - // index = 0xe - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0xf - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0x10 - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0x11 - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0x12 - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0x13 - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0x14 - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0x15 - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0x16 - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0x17 - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = 0 }, - // index = 0x18 = ELEMENT_TYPE_I - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - // index = 0x19 = ELEMENT_TYPE_U - new RhCorElementTypeInfo { _widenMask = 0x0000, _flags = RhCorElementTypeInfoFlags.IsValid|RhCorElementTypeInfoFlags.IsPrimitive }, - }; - } } }