-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Move unboxing helpers to managed code #109135
Changes from 18 commits
c70a57c
f1258a4
02636f8
d8e01e3
b2c6991
12d17e5
3f281b9
8dfaedc
be624da
dec085f
e22038b
e44fab4
2964105
6469fbb
1e51dd2
ee6d42d
7761ad8
55e0df9
6a8d1ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -448,9 +448,6 @@ internal static unsafe bool ObjectHasComponentSize(object obj) | |||||||||
[MethodImpl(MethodImplOptions.InternalCall)] | ||||||||||
internal static extern unsafe object? Box(MethodTable* methodTable, ref byte data); | ||||||||||
|
||||||||||
[MethodImpl(MethodImplOptions.InternalCall)] | ||||||||||
internal static extern unsafe void Unbox_Nullable(ref byte destination, MethodTable* toTypeHnd, object? obj); | ||||||||||
|
||||||||||
// Given an object reference, returns its MethodTable*. | ||||||||||
// | ||||||||||
// WARNING: The caller has to ensure that MethodTable* does not get unloaded. The most robust way | ||||||||||
|
@@ -706,12 +703,41 @@ internal unsafe struct MethodTable | |||||||||
[FieldOffset(ElementTypeOffset)] | ||||||||||
public void* ElementType; | ||||||||||
|
||||||||||
/// <summary> | ||||||||||
/// The PerInstInfo is used to describe the generic arguments and dictionary of this type. | ||||||||||
/// It points as a PerInstInfo, which is an array of pointers to generic dictionaries, which then point | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This does not parse for me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated the wording. Hopefully it is a bit more clear although for sure, the actual design of this is a very confusing structure. |
||||||||||
/// to the actual type arguments + the contents of the generic dictionary. The size of the PerInstInfo is | ||||||||||
/// defined in the negative space of that structure, and the size of the generic dictionary is described | ||||||||||
/// in the DictionaryLayout of the associated canonical MethodTable. | ||||||||||
/// </summary> | ||||||||||
[FieldOffset(ElementTypeOffset)] | ||||||||||
public MethodTable*** PerInstInfo; | ||||||||||
|
||||||||||
/// <summary> | ||||||||||
/// This interface map used to list out the set of interfaces. Only meaningful if InterfaceCount is non-zero. | ||||||||||
/// </summary> | ||||||||||
[FieldOffset(InterfaceMapOffset)] | ||||||||||
public MethodTable** InterfaceMap; | ||||||||||
|
||||||||||
/// <summary> | ||||||||||
/// This is used to hold the nullable unbox data for nullable value types. | ||||||||||
/// </summary> | ||||||||||
[FieldOffset(InterfaceMapOffset)] | ||||||||||
#if TARGET_64BIT | ||||||||||
public uint NullableValueAddrOffset; | ||||||||||
#else | ||||||||||
public byte NullableValueAddrOffset; | ||||||||||
#endif | ||||||||||
|
||||||||||
#if TARGET_64BIT | ||||||||||
[FieldOffset(InterfaceMapOffset + 4)] | ||||||||||
public uint NullableValueSize; | ||||||||||
#else | ||||||||||
[FieldOffset(InterfaceMapOffset)] | ||||||||||
private uint NullableValueSizeEncoded; | ||||||||||
public uint NullableValueSize => NullableValueSizeEncoded >> 8; | ||||||||||
#endif | ||||||||||
|
||||||||||
// WFLAGS_LOW_ENUM | ||||||||||
private const uint enum_flag_GenericsMask = 0x00000030; | ||||||||||
private const uint enum_flag_GenericsMask_NonGeneric = 0x00000000; // no instantiation | ||||||||||
|
@@ -730,6 +756,7 @@ internal unsafe struct MethodTable | |||||||||
private const uint enum_flag_Category_Mask = 0x000F0000; | ||||||||||
private const uint enum_flag_Category_ValueType = 0x00040000; | ||||||||||
private const uint enum_flag_Category_Nullable = 0x00050000; | ||||||||||
private const uint enum_flag_Category_IsPrimitiveMask = 0x000E0000; | ||||||||||
private const uint enum_flag_Category_PrimitiveValueType = 0x00060000; // sub-category of ValueType, Enum or primitive value type | ||||||||||
private const uint enum_flag_Category_TruePrimitive = 0x00070000; // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.) | ||||||||||
private const uint enum_flag_Category_Array = 0x00080000; | ||||||||||
|
@@ -780,7 +807,9 @@ internal unsafe struct MethodTable | |||||||||
|
||||||||||
public bool NonTrivialInterfaceCast => (Flags & enum_flag_NonTrivialInterfaceCast) != 0; | ||||||||||
|
||||||||||
#if FEATURE_TYPEEQUIVALENCE | ||||||||||
public bool HasTypeEquivalence => (Flags & enum_flag_HasTypeEquivalence) != 0; | ||||||||||
#endif // FEATURE_TYPEEQUIVALENCE | ||||||||||
|
||||||||||
public bool HasFinalizer => (Flags & enum_flag_HasFinalizer) != 0; | ||||||||||
|
||||||||||
|
@@ -815,12 +844,13 @@ public int MultiDimensionalArrayRank | |||||||||
|
||||||||||
public bool IsValueType => (Flags & enum_flag_Category_ValueType_Mask) == enum_flag_Category_ValueType; | ||||||||||
|
||||||||||
public bool IsNullable => (Flags & enum_flag_Category_Mask) == enum_flag_Category_Nullable; | ||||||||||
|
||||||||||
public bool IsNullable { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (Flags & enum_flag_Category_Mask) == enum_flag_Category_Nullable; } } | ||||||||||
|
||||||||||
public bool IsByRefLike => (Flags & (enum_flag_HasComponentSize | enum_flag_IsByRefLike)) == enum_flag_IsByRefLike; | ||||||||||
|
||||||||||
// Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums. | ||||||||||
public bool IsPrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_PrimitiveValueType or enum_flag_Category_TruePrimitive; | ||||||||||
public bool IsPrimitive => (Flags & enum_flag_Category_IsPrimitiveMask) == enum_flag_Category_PrimitiveValueType; | ||||||||||
|
||||||||||
public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_TruePrimitive; | ||||||||||
|
||||||||||
|
@@ -877,6 +907,25 @@ public TypeHandle GetArrayElementTypeHandle() | |||||||||
/// </summary> | ||||||||||
[MethodImpl(MethodImplOptions.InternalCall)] | ||||||||||
public extern MethodTable* GetMethodTableMatchingParentClass(MethodTable* parent); | ||||||||||
|
||||||||||
[MethodImpl(MethodImplOptions.InternalCall)] | ||||||||||
public extern MethodTable* InstantiationArg0(); | ||||||||||
|
||||||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||||||
public uint GetNullableNumInstanceFieldBytes() | ||||||||||
{ | ||||||||||
Debug.Assert(IsNullable); | ||||||||||
Debug.Assert((NullableValueAddrOffset + NullableValueSize) == GetNumInstanceFieldBytes()); | ||||||||||
return NullableValueAddrOffset + NullableValueSize; | ||||||||||
} | ||||||||||
|
||||||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||||||
public uint GetNumInstanceFieldBytesIfContainsGCPointers() | ||||||||||
{ | ||||||||||
Debug.Assert(ContainsGCPointers); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
Debug.Assert((BaseSize - (nuint)(2 * sizeof(IntPtr)) == GetNumInstanceFieldBytes())); | ||||||||||
return BaseSize - (uint)(2 * sizeof(IntPtr)); | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
[StructLayout(LayoutKind.Sequential)] | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.