Skip to content

Commit d45854c

Browse files
authored
Convert a few reflection FCalls to C# (#92512)
* Convert a few reflection FCalls to C# * Use IsActualValueType in more places * Delete fixed TODO * Better comment
1 parent 9356b47 commit d45854c

File tree

18 files changed

+124
-188
lines changed

18 files changed

+124
-188
lines changed

src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ public override void SetValue(object? obj, object? value, BindingFlags invokeAtt
197197
RuntimeType fieldType = (RuntimeType)FieldType;
198198
if (value is null)
199199
{
200-
if (RuntimeTypeHandle.IsValueType(fieldType))
200+
if (fieldType.IsActualValueType)
201201
{
202202
fieldType.CheckValue(ref value, binder, culture, invokeAttr);
203203
}

src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ private static CustomAttributeEncoding TypeToCustomAttributeEncoding(RuntimeType
114114
if (type == typeof(int))
115115
return CustomAttributeEncoding.Int32;
116116

117-
if (type.IsEnum)
117+
if (type.IsActualEnum)
118118
return CustomAttributeEncoding.Enum;
119119

120120
if (type == typeof(string))
@@ -172,7 +172,7 @@ private static CustomAttributeEncoding TypeToCustomAttributeEncoding(RuntimeType
172172
if (type.IsInterface)
173173
return CustomAttributeEncoding.Object;
174174

175-
if (type.IsValueType)
175+
if (type.IsActualValueType)
176176
return CustomAttributeEncoding.Undefined;
177177

178178
throw new ArgumentException(SR.Argument_InvalidKindOfTypeForCA, nameof(type));
@@ -1477,7 +1477,7 @@ internal static object[] CreateAttributeArrayHelper(RuntimeType caType, int elem
14771477
{
14781478
useAttributeArray = true;
14791479
}
1480-
else if (caType.IsValueType)
1480+
else if (caType.IsActualValueType)
14811481
{
14821482
useObjectArray = true;
14831483
}

src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,7 @@ internal unsafe struct MethodTable
478478
private const uint enum_flag_GenericsMask_SharedInst = 0x00000020; // shared instantiation, e.g. List<__Canon> or List<MyValueType<__Canon>>
479479
private const uint enum_flag_GenericsMask_TypicalInst = 0x00000030; // the type instantiated at its formal parameters, e.g. List<T>
480480
private const uint enum_flag_HasDefaultCtor = 0x00000200;
481+
private const uint enum_flag_IsByRefLike = 0x00001000;
481482

482483
// WFLAGS_HIGH_ENUM
483484
private const uint enum_flag_ContainsPointers = 0x01000000;
@@ -487,6 +488,7 @@ internal unsafe struct MethodTable
487488
private const uint enum_flag_Category_ValueType = 0x00040000;
488489
private const uint enum_flag_Category_Nullable = 0x00050000;
489490
private const uint enum_flag_Category_ValueType_Mask = 0x000C0000;
491+
private const uint enum_flag_Category_Interface = 0x000C0000;
490492
// Types that require non-trivial interface cast have this bit set in the category
491493
private const uint enum_flag_NonTrivialInterfaceCast = 0x00080000 // enum_flag_Category_Array
492494
| 0x40000000 // enum_flag_ComObject
@@ -555,10 +557,14 @@ public int MultiDimensionalArrayRank
555557
}
556558
}
557559

560+
public bool IsInterface => (Flags & enum_flag_Category_Mask) == enum_flag_Category_Interface;
561+
558562
public bool IsValueType => (Flags & enum_flag_Category_ValueType_Mask) == enum_flag_Category_ValueType;
559563

560564
public bool IsNullable => (Flags & enum_flag_Category_Mask) == enum_flag_Category_Nullable;
561565

566+
public bool IsByRefLike => (Flags & (enum_flag_HasComponentSize | enum_flag_IsByRefLike)) == enum_flag_IsByRefLike;
567+
562568
public bool HasInstantiation => (Flags & enum_flag_HasComponentSize) == 0 && (Flags & enum_flag_GenericsMask) != enum_flag_GenericsMask_NonGeneric;
563569

564570
public bool IsGenericTypeDefinition => (Flags & (enum_flag_HasComponentSize | enum_flag_GenericsMask)) == enum_flag_GenericsMask_TypicalInst;

src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -463,12 +463,6 @@ internal static bool IsComObject(RuntimeType type, bool isGenericCOM)
463463
#endif
464464
}
465465

466-
[MethodImpl(MethodImplOptions.InternalCall)]
467-
internal static extern bool IsInterface(RuntimeType type);
468-
469-
[MethodImpl(MethodImplOptions.InternalCall)]
470-
internal static extern bool IsByRefLike(RuntimeType type);
471-
472466
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_IsVisible")]
473467
[return: MarshalAs(UnmanagedType.Bool)]
474468
private static partial bool _IsVisible(QCallTypeHandle typeHandle);
@@ -478,9 +472,6 @@ internal static bool IsVisible(RuntimeType type)
478472
return _IsVisible(new QCallTypeHandle(ref type));
479473
}
480474

481-
[MethodImpl(MethodImplOptions.InternalCall)]
482-
internal static extern bool IsValueType(RuntimeType type);
483-
484475
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_ConstructName")]
485476
private static partial void ConstructName(QCallTypeHandle handle, TypeNameFormatFlags formatFlags, StringHandleOnStack retString);
486477

src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,7 @@ private unsafe RuntimeMethodInfo[] PopulateMethods(Filter filter)
599599
RuntimeType declaringType = ReflectedType;
600600
Debug.Assert(declaringType != null);
601601

602-
if (RuntimeTypeHandle.IsInterface(declaringType))
602+
if (declaringType.IsInterface)
603603
{
604604
#region IsInterface
605605

@@ -653,7 +653,7 @@ private unsafe RuntimeMethodInfo[] PopulateMethods(Filter filter)
653653
bool* overrides = stackalloc bool[numVirtuals];
654654
new Span<bool>(overrides, numVirtuals).Clear();
655655

656-
bool isValueType = declaringType.IsValueType;
656+
bool isValueType = declaringType.IsActualValueType;
657657

658658
do
659659
{
@@ -1144,7 +1144,7 @@ private RuntimeEventInfo[] PopulateEvents(Filter filter)
11441144
RuntimeType declaringType = ReflectedType;
11451145
ListBuilder<RuntimeEventInfo> list = default;
11461146

1147-
if (!RuntimeTypeHandle.IsInterface(declaringType))
1147+
if (!declaringType.IsInterface)
11481148
{
11491149
while (RuntimeTypeHandle.IsGenericVariable(declaringType))
11501150
declaringType = declaringType.GetBaseType()!;
@@ -1234,7 +1234,7 @@ private RuntimePropertyInfo[] PopulateProperties(Filter filter)
12341234

12351235
ListBuilder<RuntimePropertyInfo> list = default;
12361236

1237-
if (!RuntimeTypeHandle.IsInterface(declaringType))
1237+
if (!declaringType.IsInterface)
12381238
{
12391239
while (RuntimeTypeHandle.IsGenericVariable(declaringType))
12401240
declaringType = declaringType.GetBaseType()!;
@@ -3382,6 +3382,19 @@ protected override unsafe bool IsValueTypeImpl()
33823382
return isValueType;
33833383
}
33843384

3385+
// This returns true for actual value types only, ignoring generic parameter constraints.
3386+
internal unsafe bool IsActualValueType
3387+
{
3388+
get
3389+
{
3390+
TypeHandle th = GetNativeTypeHandle();
3391+
3392+
bool isValueType = !th.IsTypeDesc && th.AsMethodTable()->IsValueType;
3393+
GC.KeepAlive(this);
3394+
return isValueType;
3395+
}
3396+
}
3397+
33853398
public override unsafe bool IsEnum
33863399
{
33873400
get
@@ -3398,7 +3411,7 @@ public override unsafe bool IsEnum
33983411
}
33993412
}
34003413

3401-
// This returns true for actual enum types only.
3414+
// This returns true for actual enum types only, ignoring generic parameter constraints.
34023415
internal unsafe bool IsActualEnum
34033416
{
34043417
[Intrinsic]
@@ -3412,6 +3425,30 @@ internal unsafe bool IsActualEnum
34123425
}
34133426
}
34143427

3428+
internal new unsafe bool IsInterface
3429+
{
3430+
get
3431+
{
3432+
TypeHandle th = GetNativeTypeHandle();
3433+
3434+
bool isInterface = !th.IsTypeDesc && th.AsMethodTable()->IsInterface;
3435+
GC.KeepAlive(this);
3436+
return isInterface;
3437+
}
3438+
}
3439+
3440+
public override unsafe bool IsByRefLike
3441+
{
3442+
get
3443+
{
3444+
TypeHandle th = GetNativeTypeHandle();
3445+
3446+
bool isByRefLike = !th.IsTypeDesc && th.AsMethodTable()->IsByRefLike;
3447+
GC.KeepAlive(this);
3448+
return isByRefLike;
3449+
}
3450+
}
3451+
34153452
internal unsafe bool IsDelegate()
34163453
{
34173454
TypeHandle th = GetNativeTypeHandle();

src/coreclr/System.Private.CoreLib/src/System/Type.CoreCLR.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,6 @@ namespace System
1212
{
1313
public abstract partial class Type : MemberInfo, IReflect
1414
{
15-
public bool IsInterface
16-
{
17-
get
18-
{
19-
if (this is RuntimeType rt)
20-
return RuntimeTypeHandle.IsInterface(rt);
21-
return (GetAttributeFlagsImpl() & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
22-
}
23-
}
24-
2515
[RequiresUnreferencedCode("The type might be removed")]
2616
[DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
2717
public static Type? GetType(string typeName, bool throwOnError, bool ignoreCase)

src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,6 @@
240240
<Compile Include="System\Threading\SyncTable.cs" />
241241
<Compile Include="System\Threading\Thread.NativeAot.cs" />
242242
<Compile Include="System\Type.NativeAot.cs" />
243-
<Compile Include="System\Type.Internal.cs" />
244243
<Compile Include="System\TypedReference.cs" />
245244
<Compile Include="System\TypeUnificationKey.cs" />
246245
<Compile Include="System\TypeLoadException.NativeAot.cs" />

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.Internal.cs

Lines changed: 0 additions & 67 deletions
This file was deleted.

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Diagnostics.CodeAnalysis;
56
using System.Reflection;
67
using System.Runtime.CompilerServices;
@@ -18,8 +19,6 @@ namespace System
1819
{
1920
public abstract partial class Type : MemberInfo, IReflect
2021
{
21-
public bool IsInterface => (GetAttributeFlagsImpl() & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
22-
2322
[Intrinsic]
2423
public static unsafe Type? GetTypeFromHandle(RuntimeTypeHandle handle) => handle.IsNull ? null : GetTypeFromMethodTable(handle.ToMethodTable());
2524

@@ -65,6 +64,54 @@ private static unsafe Type GetTypeFromMethodTableSlow(MethodTable* pMT, ref GCHa
6564
return result;
6665
}
6766

67+
internal EETypePtr GetEEType()
68+
{
69+
RuntimeTypeHandle typeHandle = RuntimeAugments.Callbacks.GetTypeHandleIfAvailable(this);
70+
Debug.Assert(!typeHandle.IsNull);
71+
return typeHandle.ToEETypePtr();
72+
}
73+
74+
internal bool TryGetEEType(out EETypePtr eeType)
75+
{
76+
RuntimeTypeHandle typeHandle = RuntimeAugments.Callbacks.GetTypeHandleIfAvailable(this);
77+
if (typeHandle.IsNull)
78+
{
79+
eeType = default(EETypePtr);
80+
return false;
81+
}
82+
eeType = typeHandle.ToEETypePtr();
83+
return true;
84+
}
85+
86+
//
87+
// This is a port of the desktop CLR's RuntimeType.FormatTypeName() routine. This routine is used by various Reflection ToString() methods
88+
// to display the name of a type. Do not use for any other purpose as it inherits some pretty quirky desktop behavior.
89+
//
90+
internal string FormatTypeNameForReflection()
91+
{
92+
// Legacy: this doesn't make sense, why use only Name for nested types but otherwise
93+
// ToString() which contains namespace.
94+
Type rootElementType = this;
95+
while (rootElementType.HasElementType)
96+
rootElementType = rootElementType.GetElementType()!;
97+
if (rootElementType.IsNested)
98+
{
99+
return Name!;
100+
}
101+
102+
// Legacy: why removing "System"? Is it just because C# has keywords for these types?
103+
// If so why don't we change it to lower case to match the C# keyword casing?
104+
string typeName = ToString();
105+
if (typeName.StartsWith("System."))
106+
{
107+
if (rootElementType.IsPrimitive || rootElementType == typeof(void))
108+
{
109+
typeName = typeName.Substring("System.".Length);
110+
}
111+
}
112+
return typeName;
113+
}
114+
68115
[Intrinsic]
69116
[RequiresUnreferencedCode("The type might be removed")]
70117
public static Type GetType(string typeName) => GetType(typeName, throwOnError: false, ignoreCase: false);

src/coreclr/vm/ecalllist.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,6 @@ FCFuncStart(gCOMTypeHandleFuncs)
156156
FCFuncElement("_GetMetadataImport", RuntimeTypeHandle::GetMetadataImport)
157157
FCFuncElement("GetNumVirtuals", RuntimeTypeHandle::GetNumVirtuals)
158158
FCFuncElement("GetNumVirtualsAndStaticVirtuals", RuntimeTypeHandle::GetNumVirtualsAndStaticVirtuals)
159-
FCFuncElement("IsValueType", RuntimeTypeHandle::IsValueType)
160-
FCFuncElement("IsInterface", RuntimeTypeHandle::IsInterface)
161-
FCFuncElement("IsByRefLike", RuntimeTypeHandle::IsByRefLike)
162159
FCFuncElement("CanCastTo", RuntimeTypeHandle::CanCastTo)
163160
FCFuncElement("GetGenericVariableIndex", RuntimeTypeHandle::GetGenericVariableIndex)
164161
FCFuncElement("IsGenericVariable", RuntimeTypeHandle::IsGenericVariable)

0 commit comments

Comments
 (0)