| File: Utils\MethodTable.cs | Web Access |
| Project: src\src\Microsoft.ML.TorchSharp\Microsoft.ML.TorchSharp.csproj (Microsoft.ML.TorchSharp) |
// 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(); } }