| File: System\Reflection\Metadata\IL\MethodBodyBlock.cs | Web Access |
| Project: src\runtime\src\libraries\System.Reflection.Metadata\src\System.Reflection.Metadata.csproj (System.Reflection.Metadata) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; using System.Diagnostics; using System.Reflection.Internal; using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; namespace System.Reflection.Metadata { public sealed class MethodBodyBlock { private readonly MemoryBlock _il; private readonly int _size; private readonly ushort _maxStack; private readonly bool _localVariablesInitialized; private readonly StandaloneSignatureHandle _localSignature; private readonly ImmutableArray<ExceptionRegion> _exceptionRegions; private MethodBodyBlock( bool localVariablesInitialized, ushort maxStack, StandaloneSignatureHandle localSignatureHandle, MemoryBlock il, ImmutableArray<ExceptionRegion> exceptionRegions, int size) { Debug.Assert(!exceptionRegions.IsDefault); _localVariablesInitialized = localVariablesInitialized; _maxStack = maxStack; _localSignature = localSignatureHandle; _il = il; _exceptionRegions = exceptionRegions; _size = size; } /// <summary> /// Size of the method body - includes the header, IL and exception regions. /// </summary> public int Size { get { return _size; } } public int MaxStack { get { return _maxStack; } } public bool LocalVariablesInitialized { get { return _localVariablesInitialized; } } public StandaloneSignatureHandle LocalSignature { get { return _localSignature; } } public ImmutableArray<ExceptionRegion> ExceptionRegions { get { return _exceptionRegions; } } public byte[]? GetILBytes() { return _il.ToArray(); } public ImmutableArray<byte> GetILContent() { byte[]? bytes = GetILBytes(); return ImmutableCollectionsMarshal.AsImmutableArray(bytes); } public BlobReader GetILReader() { return new BlobReader(_il); } private const byte ILTinyFormat = 0x02; private const byte ILFatFormat = 0x03; private const byte ILFormatMask = 0x03; private const int ILTinyFormatSizeShift = 2; private const byte ILMoreSects = 0x08; private const byte ILInitLocals = 0x10; private const byte ILFatFormatHeaderSize = 0x03; private const int ILFatFormatHeaderSizeShift = 4; private const byte SectEHTable = 0x01; private const byte SectFatFormat = 0x40; public static MethodBodyBlock Create(BlobReader reader) { int startOffset = reader.Offset; int ilSize; // Error need to check if the Memory Block is empty. This is false for all the calls... byte headByte = reader.ReadByte(); if ((headByte & ILFormatMask) == ILTinyFormat) { // tiny IL can't have locals so technically this shouldn't matter, // but false is consistent with other metadata readers and helps // for use cases involving comparing our output with theirs. const bool initLocalsForTinyIL = false; ilSize = headByte >> ILTinyFormatSizeShift; return new MethodBodyBlock( initLocalsForTinyIL, 8, default(StandaloneSignatureHandle), reader.GetMemoryBlockAt(0, ilSize), ImmutableArray<ExceptionRegion>.Empty, 1 + ilSize // header + IL ); } if ((headByte & ILFormatMask) != ILFatFormat) { throw new BadImageFormatException(SR.Format(SR.InvalidMethodHeader1, headByte)); } // FatILFormat byte headByte2 = reader.ReadByte(); if ((headByte2 >> ILFatFormatHeaderSizeShift) != ILFatFormatHeaderSize) { throw new BadImageFormatException(SR.Format(SR.InvalidMethodHeader2, headByte, headByte2)); } bool localsInitialized = (headByte & ILInitLocals) == ILInitLocals; bool hasExceptionHandlers = (headByte & ILMoreSects) == ILMoreSects; ushort maxStack = reader.ReadUInt16(); ilSize = reader.ReadInt32(); int localSignatureToken = reader.ReadInt32(); StandaloneSignatureHandle localSignatureHandle; if (localSignatureToken == 0) { localSignatureHandle = default(StandaloneSignatureHandle); } else if ((localSignatureToken & TokenTypeIds.TypeMask) == TokenTypeIds.Signature) { localSignatureHandle = StandaloneSignatureHandle.FromRowId((int)((uint)localSignatureToken & TokenTypeIds.RIDMask)); } else { throw new BadImageFormatException(SR.Format(SR.InvalidLocalSignatureToken, unchecked((uint)localSignatureToken))); } var ilBlock = reader.GetMemoryBlockAt(0, ilSize); reader.Offset += ilSize; ImmutableArray<ExceptionRegion> exceptionHandlers; if (hasExceptionHandlers) { reader.Align(4); byte sehHeader = reader.ReadByte(); if ((sehHeader & SectEHTable) != SectEHTable) { throw new BadImageFormatException(SR.Format(SR.InvalidSehHeader, sehHeader)); } bool sehFatFormat = (sehHeader & SectFatFormat) == SectFatFormat; int dataSize = reader.ReadByte(); if (sehFatFormat) { dataSize += reader.ReadUInt16() << 8; exceptionHandlers = ReadFatExceptionHandlers(ref reader, dataSize / 24); } else { reader.Offset += 2; // skip over reserved field exceptionHandlers = ReadSmallExceptionHandlers(ref reader, dataSize / 12); } } else { exceptionHandlers = ImmutableArray<ExceptionRegion>.Empty; } return new MethodBodyBlock( localsInitialized, maxStack, localSignatureHandle, ilBlock, exceptionHandlers, reader.Offset - startOffset); } private static ImmutableArray<ExceptionRegion> ReadSmallExceptionHandlers(ref BlobReader memReader, int count) { var result = ImmutableArray.CreateBuilder<ExceptionRegion>(count); for (int i = 0; i < count; i++) { var kind = (ExceptionRegionKind)memReader.ReadUInt16(); var tryOffset = memReader.ReadUInt16(); var tryLength = memReader.ReadByte(); var handlerOffset = memReader.ReadUInt16(); var handlerLength = memReader.ReadByte(); var classTokenOrFilterOffset = memReader.ReadInt32(); result.Add(new ExceptionRegion(kind, tryOffset, tryLength, handlerOffset, handlerLength, classTokenOrFilterOffset)); } return result.MoveToImmutable(); } private static ImmutableArray<ExceptionRegion> ReadFatExceptionHandlers(ref BlobReader memReader, int count) { var result = ImmutableArray.CreateBuilder<ExceptionRegion>(count); for (int i = 0; i < count; i++) { var kind = (ExceptionRegionKind)memReader.ReadUInt32(); int tryOffset = memReader.ReadInt32(); int tryLength = memReader.ReadInt32(); int handlerOffset = memReader.ReadInt32(); int handlerLength = memReader.ReadInt32(); int classTokenOrFilterOffset = memReader.ReadInt32(); result.Add(new ExceptionRegion(kind, tryOffset, tryLength, handlerOffset, handlerLength, classTokenOrFilterOffset)); } return result.MoveToImmutable(); } } }