< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 100
Coverable lines: 100
Total lines: 295
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 46
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
IsSmallRegionCount(...)100%110%
IsSmallExceptionRegion(...)0%220%
IsSmallExceptionRegionFromBounds(...)100%110%
GetExceptionTableSize(...)0%220%
IsExceptionRegionCountInBounds(...)100%110%
IsValidCatchTypeHandle(...)0%660%
SerializeTableHeader(...)0%440%
AddFinally(...)100%110%
AddFault(...)100%110%
AddCatch(...)100%110%
AddFilter(...)100%110%
Add(...)0%30300%
AddUnchecked(...)0%220%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/ExceptionRegionEncoder.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5
 6namespace System.Reflection.Metadata.Ecma335
 7{
 8    public readonly struct ExceptionRegionEncoder
 9    {
 10        private const int TableHeaderSize = 4;
 11
 12        private const int SmallRegionSize =
 13            sizeof(short) +  // Flags
 14            sizeof(short) +  // TryOffset
 15            sizeof(byte) +   // TryLength
 16            sizeof(short) +  // HandlerOffset
 17            sizeof(byte) +   // HandleLength
 18            sizeof(int);     // ClassToken | FilterOffset
 19
 20        private const int FatRegionSize =
 21            sizeof(int) +    // Flags
 22            sizeof(int) +    // TryOffset
 23            sizeof(int) +    // TryLength
 24            sizeof(int) +    // HandlerOffset
 25            sizeof(int) +    // HandleLength
 26            sizeof(int);     // ClassToken | FilterOffset
 27
 28        private const int ThreeBytesMaxValue = 0xffffff;
 29        internal const int MaxSmallExceptionRegions = (byte.MaxValue - TableHeaderSize) / SmallRegionSize;
 30        internal const int MaxExceptionRegions = (ThreeBytesMaxValue - TableHeaderSize) / FatRegionSize;
 31
 32        /// <summary>
 33        /// The underlying builder.
 34        /// </summary>
 035        public BlobBuilder Builder { get; }
 36
 37        /// <summary>
 38        /// True if the encoder uses small format.
 39        /// </summary>
 040        public bool HasSmallFormat { get; }
 41
 42        internal ExceptionRegionEncoder(BlobBuilder builder, bool hasSmallFormat)
 043        {
 044            Builder = builder;
 045            HasSmallFormat = hasSmallFormat;
 046        }
 47
 48        /// <summary>
 49        /// Returns true if the number of exception regions first small format.
 50        /// </summary>
 51        /// <param name="exceptionRegionCount">Number of exception regions.</param>
 52        public static bool IsSmallRegionCount(int exceptionRegionCount) =>
 053            unchecked((uint)exceptionRegionCount) <= MaxSmallExceptionRegions;
 54
 55        /// <summary>
 56        /// Returns true if the region fits small format.
 57        /// </summary>
 58        /// <param name="startOffset">Start offset of the region.</param>
 59        /// <param name="length">Length of the region.</param>
 60        public static bool IsSmallExceptionRegion(int startOffset, int length) =>
 061            unchecked((uint)startOffset) <= ushort.MaxValue && unchecked((uint)length) <= byte.MaxValue;
 62
 63        internal static bool IsSmallExceptionRegionFromBounds(int startOffset, int endOffset) =>
 064            IsSmallExceptionRegion(startOffset, endOffset - startOffset);
 65
 66        internal static int GetExceptionTableSize(int exceptionRegionCount, bool isSmallFormat) =>
 067            TableHeaderSize + exceptionRegionCount * (isSmallFormat ? SmallRegionSize : FatRegionSize);
 68
 69        internal static bool IsExceptionRegionCountInBounds(int exceptionRegionCount) =>
 070            unchecked((uint)exceptionRegionCount) <= MaxExceptionRegions;
 71
 72        internal static bool IsValidCatchTypeHandle(EntityHandle catchType)
 073        {
 074            return !catchType.IsNil &&
 075                   (catchType.Kind == HandleKind.TypeDefinition ||
 076                    catchType.Kind == HandleKind.TypeSpecification ||
 077                    catchType.Kind == HandleKind.TypeReference);
 078        }
 79
 80        internal static ExceptionRegionEncoder SerializeTableHeader(BlobBuilder builder, int exceptionRegionCount, bool 
 081        {
 082            Debug.Assert(exceptionRegionCount > 0);
 83
 84            const byte EHTableFlag = 0x01;
 85            const byte FatFormatFlag = 0x40;
 86
 087            bool hasSmallFormat = hasSmallRegions && IsSmallRegionCount(exceptionRegionCount);
 088            int dataSize = GetExceptionTableSize(exceptionRegionCount, hasSmallFormat);
 89
 090            builder.Align(4);
 091            if (hasSmallFormat)
 092            {
 093                builder.WriteByte(EHTableFlag);
 094                builder.WriteByte(unchecked((byte)dataSize));
 095                builder.WriteInt16(0);
 096            }
 97            else
 098            {
 099                Debug.Assert(dataSize <= 0x00ffffff);
 0100                builder.WriteByte(EHTableFlag | FatFormatFlag);
 0101                builder.WriteByte(unchecked((byte)dataSize));
 0102                builder.WriteUInt16(unchecked((ushort)(dataSize >> 8)));
 0103            }
 104
 0105            return new ExceptionRegionEncoder(builder, hasSmallFormat);
 0106        }
 107
 108        /// <summary>
 109        /// Adds a finally clause.
 110        /// </summary>
 111        /// <param name="tryOffset">Try block start offset.</param>
 112        /// <param name="tryLength">Try block length.</param>
 113        /// <param name="handlerOffset">Handler start offset.</param>
 114        /// <param name="handlerLength">Handler length.</param>
 115        /// <returns>Encoder for the next clause.</returns>
 116        /// <exception cref="ArgumentOutOfRangeException">
 117        /// <paramref name="tryOffset"/>, <paramref name="tryLength"/>, <paramref name="handlerOffset"/> or <paramref na
 118        /// </exception>
 119        /// <exception cref="InvalidOperationException">Method body was not declared to have exception regions.</excepti
 120        public ExceptionRegionEncoder AddFinally(int tryOffset, int tryLength, int handlerOffset, int handlerLength)
 0121        {
 0122            return Add(ExceptionRegionKind.Finally, tryOffset, tryLength, handlerOffset, handlerLength, default(EntityHa
 0123        }
 124
 125        /// <summary>
 126        /// Adds a fault clause.
 127        /// </summary>
 128        /// <param name="tryOffset">Try block start offset.</param>
 129        /// <param name="tryLength">Try block length.</param>
 130        /// <param name="handlerOffset">Handler start offset.</param>
 131        /// <param name="handlerLength">Handler length.</param>
 132        /// <returns>Encoder for the next clause.</returns>
 133        /// <exception cref="ArgumentOutOfRangeException">
 134        /// <paramref name="tryOffset"/>, <paramref name="tryLength"/>, <paramref name="handlerOffset"/> or <paramref na
 135        /// </exception>
 136        /// <exception cref="InvalidOperationException">Method body was not declared to have exception regions.</excepti
 137        public ExceptionRegionEncoder AddFault(int tryOffset, int tryLength, int handlerOffset, int handlerLength)
 0138        {
 0139            return Add(ExceptionRegionKind.Fault, tryOffset, tryLength, handlerOffset, handlerLength, default(EntityHand
 0140        }
 141
 142        /// <summary>
 143        /// Adds a fault clause.
 144        /// </summary>
 145        /// <param name="tryOffset">Try block start offset.</param>
 146        /// <param name="tryLength">Try block length.</param>
 147        /// <param name="handlerOffset">Handler start offset.</param>
 148        /// <param name="handlerLength">Handler length.</param>
 149        /// <param name="catchType">
 150        /// <see cref="TypeDefinitionHandle"/>, <see cref="TypeReferenceHandle"/> or <see cref="TypeSpecificationHandle"
 151        /// </param>
 152        /// <returns>Encoder for the next clause.</returns>
 153        /// <exception cref="ArgumentException"><paramref name="catchType"/> is invalid.</exception>
 154        /// <exception cref="ArgumentOutOfRangeException">
 155        /// <paramref name="tryOffset"/>, <paramref name="tryLength"/>, <paramref name="handlerOffset"/> or <paramref na
 156        /// </exception>
 157        /// <exception cref="InvalidOperationException">Method body was not declared to have exception regions.</excepti
 158        public ExceptionRegionEncoder AddCatch(int tryOffset, int tryLength, int handlerOffset, int handlerLength, Entit
 0159        {
 0160            return Add(ExceptionRegionKind.Catch, tryOffset, tryLength, handlerOffset, handlerLength, catchType, 0);
 0161        }
 162
 163        /// <summary>
 164        /// Adds a fault clause.
 165        /// </summary>
 166        /// <param name="tryOffset">Try block start offset.</param>
 167        /// <param name="tryLength">Try block length.</param>
 168        /// <param name="handlerOffset">Handler start offset.</param>
 169        /// <param name="handlerLength">Handler length.</param>
 170        /// <param name="filterOffset">Offset of the filter block.</param>
 171        /// <returns>Encoder for the next clause.</returns>
 172        /// <exception cref="ArgumentOutOfRangeException">
 173        /// <paramref name="tryOffset"/>, <paramref name="tryLength"/>, <paramref name="handlerOffset"/> or <paramref na
 174        /// </exception>
 175        /// <exception cref="InvalidOperationException">Method body was not declared to have exception regions.</excepti
 176        public ExceptionRegionEncoder AddFilter(int tryOffset, int tryLength, int handlerOffset, int handlerLength, int 
 0177        {
 0178            return Add(ExceptionRegionKind.Filter, tryOffset, tryLength, handlerOffset, handlerLength, default(EntityHan
 0179        }
 180
 181        /// <summary>
 182        /// Adds an exception clause.
 183        /// </summary>
 184        /// <param name="kind">Clause kind.</param>
 185        /// <param name="tryOffset">Try block start offset.</param>
 186        /// <param name="tryLength">Try block length.</param>
 187        /// <param name="handlerOffset">Handler start offset.</param>
 188        /// <param name="handlerLength">Handler length.</param>
 189        /// <param name="catchType">
 190        /// <see cref="TypeDefinitionHandle"/>, <see cref="TypeReferenceHandle"/> or <see cref="TypeSpecificationHandle"
 191        /// or nil if <paramref name="kind"/> is not <see cref="ExceptionRegionKind.Catch"/>
 192        /// </param>
 193        /// <param name="filterOffset">
 194        /// Offset of the filter block, or 0 if the <paramref name="kind"/> is not <see cref="ExceptionRegionKind.Filter
 195        /// </param>
 196        /// <returns>Encoder for the next clause.</returns>
 197        /// <exception cref="ArgumentException"><paramref name="catchType"/> is invalid.</exception>
 198        /// <exception cref="ArgumentOutOfRangeException"><paramref name="kind"/> has invalid value.</exception>
 199        /// <exception cref="ArgumentOutOfRangeException">
 200        /// <paramref name="tryOffset"/>, <paramref name="tryLength"/>, <paramref name="handlerOffset"/> or <paramref na
 201        /// </exception>
 202        /// <exception cref="InvalidOperationException">Method body was not declared to have exception regions.</excepti
 203        public ExceptionRegionEncoder Add(
 204            ExceptionRegionKind kind,
 205            int tryOffset,
 206            int tryLength,
 207            int handlerOffset,
 208            int handlerLength,
 209            EntityHandle catchType = default(EntityHandle),
 210            int filterOffset = 0)
 0211        {
 0212            if (Builder == null)
 0213            {
 0214                Throw.InvalidOperation(SR.MethodHasNoExceptionRegions);
 215            }
 216
 0217            if (HasSmallFormat)
 0218            {
 0219                if (unchecked((ushort)tryOffset) != tryOffset) Throw.ArgumentOutOfRange(nameof(tryOffset));
 0220                if (unchecked((byte)tryLength) != tryLength) Throw.ArgumentOutOfRange(nameof(tryLength));
 0221                if (unchecked((ushort)handlerOffset) != handlerOffset) Throw.ArgumentOutOfRange(nameof(handlerOffset));
 0222                if (unchecked((byte)handlerLength) != handlerLength) Throw.ArgumentOutOfRange(nameof(handlerLength));
 0223            }
 224            else
 0225            {
 0226                if (tryOffset < 0) Throw.ArgumentOutOfRange(nameof(tryOffset));
 0227                if (tryLength < 0) Throw.ArgumentOutOfRange(nameof(tryLength));
 0228                if (handlerOffset < 0) Throw.ArgumentOutOfRange(nameof(handlerOffset));
 0229                if (handlerLength < 0) Throw.ArgumentOutOfRange(nameof(handlerLength));
 0230            }
 231
 232            int catchTokenOrOffset;
 0233            switch (kind)
 234            {
 235                case ExceptionRegionKind.Catch:
 0236                    if (!IsValidCatchTypeHandle(catchType))
 0237                    {
 0238                        Throw.InvalidArgument_Handle(nameof(catchType));
 239                    }
 240
 0241                    catchTokenOrOffset = MetadataTokens.GetToken(catchType);
 0242                    break;
 243
 244                case ExceptionRegionKind.Filter:
 0245                    if (filterOffset < 0)
 0246                    {
 0247                        Throw.ArgumentOutOfRange(nameof(filterOffset));
 248                    }
 249
 0250                    catchTokenOrOffset = filterOffset;
 0251                    break;
 252
 253                case ExceptionRegionKind.Finally:
 254                case ExceptionRegionKind.Fault:
 0255                    catchTokenOrOffset = 0;
 0256                    break;
 257
 258                default:
 0259                    throw new ArgumentOutOfRangeException(nameof(kind));
 260            }
 261
 0262            AddUnchecked(kind, tryOffset, tryLength, handlerOffset, handlerLength, catchTokenOrOffset);
 0263            return this;
 0264        }
 265
 266        internal void AddUnchecked(
 267            ExceptionRegionKind kind,
 268            int tryOffset,
 269            int tryLength,
 270            int handlerOffset,
 271            int handlerLength,
 272            int catchTokenOrOffset)
 0273        {
 0274            if (HasSmallFormat)
 0275            {
 0276                Builder.WriteUInt16((ushort)kind);
 0277                Builder.WriteUInt16((ushort)tryOffset);
 0278                Builder.WriteByte((byte)tryLength);
 0279                Builder.WriteUInt16((ushort)handlerOffset);
 0280                Builder.WriteByte((byte)handlerLength);
 0281            }
 282            else
 0283            {
 0284                Builder.WriteInt32((int)kind);
 0285                Builder.WriteInt32(tryOffset);
 0286                Builder.WriteInt32(tryLength);
 0287                Builder.WriteInt32(handlerOffset);
 0288                Builder.WriteInt32(handlerLength);
 0289            }
 290
 0291            Builder.WriteInt32(catchTokenOrOffset);
 0292        }
 293    }
 294}
 295