| File: RuntimeTypeSystemHelpers\MethodDescOptionalSlots.cs | Web Access |
| Project: src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Contracts\Microsoft.Diagnostics.DataContractReader.Contracts.csproj (Microsoft.Diagnostics.DataContractReader.Contracts) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; namespace Microsoft.Diagnostics.DataContractReader.RuntimeTypeSystemHelpers; // Optional slots are stored after the MethodDesc itself, packed tightly // in the order: [non-vtable; method impl; native code; async method data]. internal static class MethodDescOptionalSlots { internal static bool HasNonVtableSlot(ushort flags) => (flags & (ushort)MethodDescFlags_1.MethodDescFlags.HasNonVtableSlot) != 0; internal static bool HasMethodImpl(ushort flags) => (flags & (ushort)MethodDescFlags_1.MethodDescFlags.HasMethodImpl) != 0; internal static bool HasNativeCodeSlot(ushort flags) => (flags & (ushort)MethodDescFlags_1.MethodDescFlags.HasNativeCodeSlot) != 0; internal static bool HasAsyncMethodData(ushort flags) => (flags & (ushort)MethodDescFlags_1.MethodDescFlags.HasAsyncMethodData) != 0; internal static TargetPointer GetAddressOfNonVtableSlot(TargetPointer methodDesc, MethodClassification classification, ushort flags, Target target) { uint offset = StartOffset(classification, target); offset += NonVtableSlotOffset(flags); return methodDesc + offset; } internal static TargetPointer GetAddressOfNativeCodeSlot(TargetPointer methodDesc, MethodClassification classification, ushort flags, Target target) { uint offset = StartOffset(classification, target); offset += NativeCodeSlotOffset(flags, target); return methodDesc + offset; } internal static TargetPointer GetAddressOfAsyncMethodData(TargetPointer methodDesc, MethodClassification classification, ushort flags, Target target) { uint offset = StartOffset(classification, target); offset += AsyncMethodDataOffset(flags, target); return methodDesc + offset; } // Offset from the MethodDesc address to the start of its optional slots private static uint StartOffset(MethodClassification classification, Target target) { // See MethodDesc::GetBaseSize and s_ClassificationSizeTable // sizeof(MethodDesc), mcIL // sizeof(FCallMethodDesc), mcFCall // sizeof(PInvokeMethodDesc), mcPInvoke // sizeof(EEImplMethodDesc), mcEEImpl // sizeof(ArrayMethodDesc), mcArray // sizeof(InstantiatedMethodDesc), mcInstantiated // sizeof(CLRToCOMCallMethodDesc), mcComInterOp // sizeof(DynamicMethodDesc) mcDynamic DataType type = classification switch { MethodClassification.IL => DataType.MethodDesc, MethodClassification.FCall => DataType.FCallMethodDesc, MethodClassification.PInvoke => DataType.PInvokeMethodDesc, MethodClassification.EEImpl => DataType.EEImplMethodDesc, MethodClassification.Array => DataType.ArrayMethodDesc, MethodClassification.Instantiated => DataType.InstantiatedMethodDesc, MethodClassification.ComInterop => DataType.CLRToCOMCallMethodDesc, MethodClassification.Dynamic => DataType.DynamicMethodDesc, _ => throw new InvalidOperationException($"Unexpected method classification 0x{classification:x2} for MethodDesc") }; return target.GetTypeInfo(type).Size ?? throw new InvalidOperationException($"size of MethodDesc not known"); } // Offsets are from the start of optional slots data (so right after the MethodDesc), obtained via StartOffset private static uint NonVtableSlotOffset(ushort flags) { if (!HasNonVtableSlot(flags)) throw new InvalidOperationException("no non-vtable slot"); return 0u; } private static uint MethodImplOffset(ushort flags, Target target) { if (!HasMethodImpl(flags)) throw new InvalidOperationException("no method impl slot"); return HasNonVtableSlot(flags) ? (uint)target.PointerSize : 0; } private static uint NativeCodeSlotOffset(ushort flags, Target target) { if (!HasNativeCodeSlot(flags)) throw new InvalidOperationException("no native code slot"); uint offset = 0; if (HasNonVtableSlot(flags)) offset += target.GetTypeInfo(DataType.NonVtableSlot).Size!.Value; if (HasMethodImpl(flags)) offset += target.GetTypeInfo(DataType.MethodImpl).Size!.Value; return offset; } private static uint AsyncMethodDataOffset(ushort flags, Target target) { if (!HasAsyncMethodData(flags)) throw new InvalidOperationException("no async method data"); uint offset = 0; if (HasNonVtableSlot(flags)) offset += target.GetTypeInfo(DataType.NonVtableSlot).Size!.Value; if (HasMethodImpl(flags)) offset += target.GetTypeInfo(DataType.MethodImpl).Size!.Value; if (HasNativeCodeSlot(flags)) offset += target.GetTypeInfo(DataType.NativeCodeSlot).Size!.Value; return offset; } }