|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
namespace Microsoft.ML.TorchSharp.Utils
{
[StructLayout(LayoutKind.Explicit)]
internal unsafe struct MethodTable
{
/// <summary>
/// The low WORD of the first field is the component size for array and string types.
/// </summary>
[FieldOffset(0)]
public ushort ComponentSize;
/// <summary>
/// The flags for the current method table (only for not array or string types).
/// </summary>
[FieldOffset(0)]
#pragma warning disable IDE0044 // Add readonly modifier
#pragma warning disable MSML_PrivateFieldName // Private field name not in: _camelCase format
private uint Flags;
/// <summary>
/// The base size of the type (used when allocating an instance on the heap).
/// </summary>
[FieldOffset(4)]
public uint BaseSize;
// See additional native members in methodtable.h, not needed here yet.
// 0x8: m_wFlags2 (additional flags)
// 0xA: m_wToken (class token if it fits in 16 bits)
// 0xC: m_wNumVirtuals
/// <summary>
/// The number of interfaces implemented by the current type.
/// </summary>
[FieldOffset(0x0E)]
public ushort InterfaceCount;
// For DEBUG builds, there is a conditional field here (see methodtable.h again).
// 0x10: debug_m_szClassName (display name of the class, for the debugger)
/// <summary>
/// A pointer to the parent method table for the current one.
/// </summary>
[FieldOffset(ParentMethodTableOffset)]
public MethodTable* ParentMethodTable;
// Additional conditional fields (see methodtable.h).
// m_pLoaderModule
// m_pWriteableData
// union {
// m_pEEClass (pointer to the EE class)
// m_pCanonMT (pointer to the canonical method table)
// }
/// <summary>
/// This element type handle is in a union with additional info or a pointer to the interface map.
/// Which one is used is based on the specific method table being in used (so this field is not
/// always guaranteed to actually be a pointer to a type handle for the element type of this type).
/// </summary>
[FieldOffset(ElementTypeOffset)]
public void* ElementType;
/// <summary>
/// This interface map is a union with a multipurpose slot, so should be checked before use.
/// </summary>
[FieldOffset(InterfaceMapOffset)]
public MethodTable** InterfaceMap;
// WFLAGS_LOW_ENUM
private const uint enum_flag_GenericsMask = 0x00000030;
private const uint enum_flag_GenericsMask_NonGeneric = 0x00000000; // no instantiation
private const uint enum_flag_GenericsMask_GenericInst = 0x00000010; // regular instantiation, e.g. List<String>
private const uint enum_flag_GenericsMask_SharedInst = 0x00000020; // shared instantiation, e.g. List<__Canon> or List<MyValueType<__Canon>>
private const uint enum_flag_GenericsMask_TypicalInst = 0x00000030; // the type instantiated at its formal parameters, e.g. List<T>
private const uint enum_flag_HasDefaultCtor = 0x00000200;
// WFLAGS_HIGH_ENUM
private const uint enum_flag_ContainsPointers = 0x01000000;
private const uint enum_flag_HasComponentSize = 0x80000000;
private const uint enum_flag_HasTypeEquivalence = 0x02000000;
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_ValueType_Mask = 0x000C0000;
// Types that require non-trivial interface cast have this bit set in the category
private const uint enum_flag_NonTrivialInterfaceCast = 0x00080000 // enum_flag_Category_Array
| 0x40000000 // enum_flag_ComObject
| 0x00400000 // enum_flag_ICastable;
| 0x00200000 // enum_flag_IDynamicInterfaceCastable;
| 0x00040000; // enum_flag_Category_ValueType
private const int DebugClassNamePtr = // adjust for debug_m_szClassName
#if DEBUG
#if TARGET_64BIT
8
#else
4
#endif
#else
0
#endif
;
private const int ParentMethodTableOffset = 0x10 + DebugClassNamePtr;
#if TARGET_64BIT
private const int ElementTypeOffset = 0x30 + DebugClassNamePtr;
#else
private const int ElementTypeOffset = 0x20 + DebugClassNamePtr;
#endif
#if TARGET_64BIT
private const int InterfaceMapOffset = 0x38 + DebugClassNamePtr;
#else
private const int InterfaceMapOffset = 0x24 + DebugClassNamePtr;
#endif
public bool HasComponentSize => (Flags & enum_flag_HasComponentSize) != 0;
public bool ContainsGCPointers => (Flags & enum_flag_ContainsPointers) != 0;
public bool NonTrivialInterfaceCast => (Flags & enum_flag_NonTrivialInterfaceCast) != 0;
public bool HasTypeEquivalence => (Flags & enum_flag_HasTypeEquivalence) != 0;
internal static bool AreSameType(MethodTable* mt1, MethodTable* mt2) => mt1 == mt2;
public bool HasDefaultConstructor => (Flags & (enum_flag_HasComponentSize | enum_flag_HasDefaultCtor)) == enum_flag_HasDefaultCtor;
public bool IsMultiDimensionalArray
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
Debug.Assert(HasComponentSize);
// See comment on RawArrayData for details
return BaseSize > (uint)(3 * sizeof(IntPtr));
}
}
// Returns rank of multi-dimensional array rank, 0 for sz arrays
public int MultiDimensionalArrayRank
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
Debug.Assert(HasComponentSize);
// See comment on RawArrayData for details
return (int)((BaseSize - (uint)(3 * sizeof(IntPtr))) / (uint)(2 * sizeof(int)));
}
}
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 HasInstantiation => (Flags & enum_flag_HasComponentSize) == 0 && (Flags & enum_flag_GenericsMask) != enum_flag_GenericsMask_NonGeneric;
public bool IsGenericTypeDefinition => (Flags & (enum_flag_HasComponentSize | enum_flag_GenericsMask)) == enum_flag_GenericsMask_TypicalInst;
public bool IsConstructedGenericType
{
get
{
uint genericsFlags = Flags & (enum_flag_HasComponentSize | enum_flag_GenericsMask);
return genericsFlags == enum_flag_GenericsMask_GenericInst || genericsFlags == enum_flag_GenericsMask_SharedInst;
}
}
[MethodImpl(MethodImplOptions.InternalCall)]
public extern uint GetNumInstanceFieldBytes();
}
}
|