예제 #1
0
        /// <summary>
        /// Encodes a method body and adds it to the method body stream.
        /// </summary>
        /// <param name="codeSize">Number of bytes to be reserved for instructions.</param>
        /// <param name="maxStack">Max stack.</param>
        /// <param name="exceptionRegionCount">Number of exception regions.</param>
        /// <param name="hasSmallExceptionRegions">True if the exception regions should be encoded in 'small' format.</param>
        /// <param name="localVariablesSignature">Local variables signature handle.</param>
        /// <param name="attributes">Attributes.</param>
        /// <param name="hasDynamicStackAllocation">True if the method allocates from dynamic local memory pool (<c>localloc</c> instruction).</param>
        /// <returns>The offset of the encoded body within the method body stream.</returns>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="codeSize"/>, <paramref name="exceptionRegionCount"/>, or <paramref name="maxStack"/> is out of allowed range.
        /// </exception>
        public MethodBody AddMethodBody(
            int codeSize,
            int maxStack                  = 8,
            int exceptionRegionCount      = 0,
            bool hasSmallExceptionRegions = true,
            StandaloneSignatureHandle localVariablesSignature = default,
            MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals,
            bool hasDynamicStackAllocation  = false)
        {
            if (codeSize < 0)
            {
                Throw.ArgumentOutOfRange(nameof(codeSize));
            }

            if (unchecked ((uint)maxStack) > ushort.MaxValue)
            {
                Throw.ArgumentOutOfRange(nameof(maxStack));
            }

            if (!ExceptionRegionEncoder.IsExceptionRegionCountInBounds(exceptionRegionCount))
            {
                Throw.ArgumentOutOfRange(nameof(exceptionRegionCount));
            }

            int bodyOffset   = SerializeHeader(codeSize, (ushort)maxStack, exceptionRegionCount, attributes, localVariablesSignature, hasDynamicStackAllocation);
            var instructions = Builder.ReserveBytes(codeSize);

            var regionEncoder = (exceptionRegionCount > 0) ?
                                ExceptionRegionEncoder.SerializeTableHeader(Builder, exceptionRegionCount, hasSmallExceptionRegions) : default;

            return(new MethodBody(bodyOffset, instructions, regionEncoder));
        }
예제 #2
0
        /// <summary>
        /// Encodes a method body and adds it to the method body stream.
        /// </summary>
        /// <param name="codeSize">Number of bytes to be reserved for instructions.</param>
        /// <param name="maxStack">Max stack.</param>
        /// <param name="exceptionRegionCount">Number of exception regions.</param>
        /// <param name="hasSmallExceptionRegions">True if the exception regions should be encoded in 'small' format.</param>
        /// <param name="localVariablesSignature">Local variables signature handle.</param>
        /// <param name="attributes">Attributes.</param>
        /// <returns>The offset of the encoded body within the method body stream.</returns>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="codeSize"/>, <paramref name="exceptionRegionCount"/>, or <paramref name="maxStack"/> is out of allowed range.
        /// </exception>
        public MethodBody AddMethodBody(
            int codeSize,
            int maxStack = 8,
            int exceptionRegionCount = 0,
            bool hasSmallExceptionRegions = true,
            StandaloneSignatureHandle localVariablesSignature = default(StandaloneSignatureHandle),
            MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals)
        {
            if (codeSize < 0)
            {
                Throw.ArgumentOutOfRange(nameof(codeSize));
            }

            if (unchecked((uint)maxStack) > ushort.MaxValue)
            {
                Throw.ArgumentOutOfRange(nameof(maxStack));
            }

            if (!ExceptionRegionEncoder.IsExceptionRegionCountInBounds(exceptionRegionCount))
            {
                Throw.ArgumentOutOfRange(nameof(exceptionRegionCount));
            }

            int bodyOffset = SerializeHeader(codeSize, (ushort)maxStack, exceptionRegionCount, attributes, localVariablesSignature);
            var instructions = Builder.ReserveBytes(codeSize);

            var regionEncoder = (exceptionRegionCount > 0) ? 
                ExceptionRegionEncoder.SerializeTableHeader(Builder, exceptionRegionCount, hasSmallExceptionRegions) : default(ExceptionRegionEncoder);

            return new MethodBody(bodyOffset, instructions, regionEncoder);
        }
예제 #3
0
 /// <summary>
 /// Encodes a method body and adds it to the method body stream.
 /// </summary>
 /// <param name="codeSize">Number of bytes to be reserved for instructions.</param>
 /// <param name="maxStack">Max stack.</param>
 /// <param name="exceptionRegionCount">Number of exception regions.</param>
 /// <param name="hasSmallExceptionRegions">True if the exception regions should be encoded in 'small' format.</param>
 /// <param name="localVariablesSignature">Local variables signature handle.</param>
 /// <param name="attributes">Attributes.</param>
 /// <returns>The offset of the encoded body within the method body stream.</returns>
 /// <exception cref="ArgumentOutOfRangeException">
 /// <paramref name="codeSize"/>, <paramref name="exceptionRegionCount"/>, or <paramref name="maxStack"/> is out of allowed range.
 /// </exception>
 public MethodBody AddMethodBody(
     int codeSize,
     int maxStack,
     int exceptionRegionCount,
     bool hasSmallExceptionRegions,
     StandaloneSignatureHandle localVariablesSignature,
     MethodBodyAttributes attributes)
 => AddMethodBody(codeSize, maxStack, exceptionRegionCount, hasSmallExceptionRegions, localVariablesSignature, attributes, hasDynamicStackAllocation: false);
예제 #4
0
        /// <summary>
        /// Encodes a method body and adds it to the method body stream.
        /// </summary>
        /// <param name="instructionEncoder">Instruction encoder.</param>
        /// <param name="maxStack">Max stack.</param>
        /// <param name="localVariablesSignature">Local variables signature handle.</param>
        /// <param name="attributes">Attributes.</param>
        /// <param name="hasDynamicStackAllocation">True if the method allocates from dynamic local memory pool (the IL contains <c>localloc</c> instruction).
        /// </param>
        /// <returns>The offset of the encoded body within the method body stream.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="instructionEncoder"/> has default value.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="maxStack"/> is out of range [0, <see cref="ushort.MaxValue"/>].</exception>
        /// <exception cref="InvalidOperationException">
        /// A label targeted by a branch in the instruction stream has not been marked,
        /// or the distance between a branch instruction and the target label doesn't fit the size of the instruction operand.
        /// </exception>
        public int AddMethodBody(
            InstructionEncoder instructionEncoder,
            int maxStack = 8,
            StandaloneSignatureHandle localVariablesSignature = default,
            MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals,
            bool hasDynamicStackAllocation  = false)
        {
            if (unchecked ((uint)maxStack) > ushort.MaxValue)
            {
                Throw.ArgumentOutOfRange(nameof(maxStack));
            }

            // The branch fixup code expects the operands of branch instructions in the code builder to be contiguous.
            // That's true when we emit thru InstructionEncoder. Taking it as a parameter instead of separate
            // code and flow builder parameters ensures they match each other.
            var codeBuilder = instructionEncoder.CodeBuilder;
            var flowBuilder = instructionEncoder.ControlFlowBuilder;

            if (codeBuilder == null)
            {
                Throw.ArgumentNull(nameof(instructionEncoder));
            }

            int exceptionRegionCount = flowBuilder?.ExceptionHandlerCount ?? 0;

            if (!ExceptionRegionEncoder.IsExceptionRegionCountInBounds(exceptionRegionCount))
            {
                Throw.ArgumentOutOfRange(nameof(instructionEncoder), SR.TooManyExceptionRegions);
            }

            // Note (see also https://github.com/dotnet/corefx/issues/26910)
            //
            // We could potentially automatically determine whether a tiny method with no variables and InitLocals flag set
            // has localloc instruction and thus needs a fat header. We could parse the IL stored in codeBuilder.
            // However, it would unnecessarily slow down emit of virtually all tiny methods, which do not use localloc
            // and would only address uninitialized memory issues in very rare scenarios when the pointer returned by
            // localloc is not stored in a local variable but passed to a method call or stored in a field.
            //
            // Since emitting code with localloc is already a pretty advanced scenario that emits unsafe code
            // that can be potentially incorrect in many other ways we decide that it's not worth the complexity
            // and a perf regression to do so. Instead we rely on the caller to let us know if there is a localloc
            // in the code they emitted.

            int bodyOffset = SerializeHeader(codeBuilder.Count, (ushort)maxStack, exceptionRegionCount, attributes, localVariablesSignature, hasDynamicStackAllocation);

            if (flowBuilder?.BranchCount > 0)
            {
                flowBuilder.CopyCodeAndFixupBranches(codeBuilder, Builder);
            }
            else
            {
                codeBuilder.WriteContentTo(Builder);
            }

            flowBuilder?.SerializeExceptionTable(Builder);

            return(bodyOffset);
        }
예제 #5
0
        private int SerializeHeader(
            int codeSize,
            ushort maxStack,
            int exceptionRegionCount,
            MethodBodyAttributes attributes,
            StandaloneSignatureHandle localVariablesSignature,
            bool hasDynamicStackAllocation)
        {
            const int  TinyFormat   = 2;
            const int  FatFormat    = 3;
            const int  MoreSections = 8;
            const byte InitLocals   = 0x10;

            bool initLocals = (attributes & MethodBodyAttributes.InitLocals) != 0;

            bool isTiny = codeSize < 64 &&
                          maxStack <= 8 &&
                          localVariablesSignature.IsNil && (!hasDynamicStackAllocation || !initLocals) &&
                          exceptionRegionCount == 0;

            int offset;

            if (isTiny)
            {
                offset = Builder.Count;
                Builder.WriteByte((byte)((codeSize << 2) | TinyFormat));
            }
            else
            {
                Builder.Align(4);

                offset = Builder.Count;

                ushort flags = (3 << 12) | FatFormat;
                if (exceptionRegionCount > 0)
                {
                    flags |= MoreSections;
                }

                if (initLocals)
                {
                    flags |= InitLocals;
                }

                Builder.WriteUInt16((ushort)((int)attributes | flags));
                Builder.WriteUInt16(maxStack);
                Builder.WriteInt32(codeSize);
                Builder.WriteInt32(localVariablesSignature.IsNil ? 0 : MetadataTokens.GetToken(localVariablesSignature));
            }

            return(offset);
        }
예제 #6
0
 internal MethodBodyEncoder(
     BlobBuilder builder,
     ushort maxStack,
     int exceptionRegionCount,
     StandaloneSignatureHandle localVariablesSignature,
     MethodBodyAttributes attributes)
 {
     Builder   = builder;
     _maxStack = maxStack;
     _localVariablesSignature = localVariablesSignature;
     _attributes           = (byte)attributes;
     _exceptionRegionCount = exceptionRegionCount;
 }
예제 #7
0
 internal MethodBodyEncoder(
     BlobBuilder builder,
     ushort maxStack,
     int exceptionRegionCount,
     StandaloneSignatureHandle localVariablesSignature,
     MethodBodyAttributes attributes)
 {
     Builder = builder;
     _maxStack = maxStack;
     _localVariablesSignature = localVariablesSignature;
     _attributes = (byte)attributes;
     _exceptionRegionCount = exceptionRegionCount;
 }
예제 #8
0
        private static MethodBodyAttributes GetFatHeaderAttributes(MethodDefinition methodDef)
        {
            MethodBodyAttributes attributes = MethodBodyAttributes.FatFormat;

            if (methodDef.Body.InitLocals)
            {
                attributes |= MethodBodyAttributes.InitLocals;
            }
            if (methodDef.Body.HasExceptionHandlers)
            {
                attributes |= MethodBodyAttributes.MoreSects;
            }

            return(attributes);
        }
예제 #9
0
        public MethodBodyEncoder AddMethodBody(
            int maxStack             = 8,
            int exceptionRegionCount = 0,
            StandaloneSignatureHandle localVariablesSignature = default(StandaloneSignatureHandle),
            MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals)
        {
            if (unchecked ((ushort)maxStack) > ushort.MaxValue)
            {
                Throw.ArgumentOutOfRange(nameof(maxStack));
            }

            if (exceptionRegionCount < 0)
            {
                Throw.ArgumentOutOfRange(nameof(exceptionRegionCount));
            }

            return(new MethodBodyEncoder(Builder, (ushort)maxStack, exceptionRegionCount, localVariablesSignature, attributes));
        }
예제 #10
0
        public MethodBodyEncoder AddMethodBody(
            int maxStack = 8,
            int exceptionRegionCount = 0,
            StandaloneSignatureHandle localVariablesSignature = default(StandaloneSignatureHandle),
            MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals)
        {
            if (unchecked((ushort)maxStack) > ushort.MaxValue)
            {
                throw new ArgumentOutOfRangeException(nameof(maxStack));
            }

            if (exceptionRegionCount < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(exceptionRegionCount));
            }

            return new MethodBodyEncoder(Builder, (ushort)maxStack, exceptionRegionCount, localVariablesSignature, attributes);
        }
예제 #11
0
        /// <summary>
        /// Encodes a method body and adds it to the method body stream.
        /// </summary>
        /// <param name="instructionEncoder">Instruction encoder.</param>
        /// <param name="maxStack">Max stack.</param>
        /// <param name="localVariablesSignature">Local variables signature handle.</param>
        /// <param name="attributes">Attributes.</param>
        /// <returns>The offset of the encoded body within the method body stream.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="instructionEncoder"/> has default value.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="maxStack"/> is out of range [0, <see cref="ushort.MaxValue"/>].</exception>
        /// <exception cref="InvalidOperationException">
        /// A label targeted by a branch in the instruction stream has not been marked,
        /// or the distance between a branch instruction and the target label is doesn't fit the size of the instruction operand.
        /// </exception>
        public int AddMethodBody(
            InstructionEncoder instructionEncoder,
            int maxStack = 8,
            StandaloneSignatureHandle localVariablesSignature = default(StandaloneSignatureHandle),
            MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals)
        {
            if (unchecked ((uint)maxStack) > ushort.MaxValue)
            {
                Throw.ArgumentOutOfRange(nameof(maxStack));
            }

            // The branch fixup code expects the operands of branch instructions in the code builder to be contiguous.
            // That's true when we emit thru InstructionEncoder. Taking it as a parameter instead of separate
            // code and flow builder parameters ensures they match each other.
            var codeBuilder = instructionEncoder.CodeBuilder;
            var flowBuilder = instructionEncoder.ControlFlowBuilder;

            if (codeBuilder == null)
            {
                Throw.ArgumentNull(nameof(instructionEncoder));
            }

            int exceptionRegionCount = flowBuilder?.ExceptionHandlerCount ?? 0;

            if (!ExceptionRegionEncoder.IsExceptionRegionCountInBounds(exceptionRegionCount))
            {
                Throw.ArgumentOutOfRange(nameof(instructionEncoder), SR.TooManyExceptionRegions);
            }

            int bodyOffset = SerializeHeader(codeBuilder.Count, (ushort)maxStack, exceptionRegionCount, attributes, localVariablesSignature);

            if (flowBuilder?.BranchCount > 0)
            {
                flowBuilder.CopyCodeAndFixupBranches(codeBuilder, Builder);
            }
            else
            {
                codeBuilder.WriteContentTo(Builder);
            }

            flowBuilder?.SerializeExceptionTable(Builder);

            return(bodyOffset);
        }
예제 #12
0
 /// <summary>
 /// Encodes a method body and adds it to the method body stream.
 /// </summary>
 /// <param name="instructionEncoder">Instruction encoder.</param>
 /// <param name="maxStack">Max stack.</param>
 /// <param name="localVariablesSignature">Local variables signature handle.</param>
 /// <param name="attributes">Attributes.</param>
 /// <returns>The offset of the encoded body within the method body stream.</returns>
 /// <exception cref="ArgumentNullException"><paramref name="instructionEncoder"/> has default value.</exception>
 /// <exception cref="ArgumentOutOfRangeException"><paramref name="maxStack"/> is out of range [0, <see cref="ushort.MaxValue"/>].</exception>
 /// <exception cref="InvalidOperationException">
 /// A label targeted by a branch in the instruction stream has not been marked,
 /// or the distance between a branch instruction and the target label doesn't fit the size of the instruction operand.
 /// </exception>
 public int AddMethodBody(
     InstructionEncoder instructionEncoder,
     int maxStack,
     StandaloneSignatureHandle localVariablesSignature,
     MethodBodyAttributes attributes)
 => AddMethodBody(instructionEncoder, maxStack, localVariablesSignature, attributes, hasDynamicStackAllocation: false);
예제 #13
0
        private int SerializeHeader(int codeSize, ushort maxStack, int exceptionRegionCount, MethodBodyAttributes attributes, StandaloneSignatureHandle localVariablesSignature)
        {
            const int TinyFormat = 2;
            const int FatFormat = 3;
            const int MoreSections = 8;
            const byte InitLocals = 0x10;

            int offset;

            bool isTiny = codeSize < 64 && maxStack <= 8 && localVariablesSignature.IsNil && exceptionRegionCount == 0;

            if (isTiny)
            {
                offset = Builder.Count;
                Builder.WriteByte((byte)((codeSize << 2) | TinyFormat));
            }
            else
            {
                Builder.Align(4);

                offset = Builder.Count;

                ushort flags = (3 << 12) | FatFormat;
                if (exceptionRegionCount > 0)
                {
                    flags |= MoreSections;
                }

                if ((attributes & MethodBodyAttributes.InitLocals) != 0)
                {
                    flags |= InitLocals;
                }

                Builder.WriteUInt16((ushort)((int)attributes | flags));
                Builder.WriteUInt16(maxStack);
                Builder.WriteInt32(codeSize);
                Builder.WriteInt32(localVariablesSignature.IsNil ? 0 : MetadataTokens.GetToken(localVariablesSignature));
            }

            return offset;
        }
예제 #14
0
        /// <summary>
        /// Encodes a method body and adds it to the method body stream.
        /// </summary>
        /// <param name="instructionEncoder">Instruction encoder.</param>
        /// <param name="maxStack">Max stack.</param>
        /// <param name="localVariablesSignature">Local variables signature handle.</param>
        /// <param name="attributes">Attributes.</param>
        /// <returns>The offset of the encoded body within the method body stream.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="instructionEncoder"/> has default value.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="maxStack"/> is out of range [0, <see cref="ushort.MaxValue"/>].</exception>
        /// <exception cref="InvalidOperationException">
        /// A label targeted by a branch in the instruction stream has not been marked,
        /// or the distance between a branch instruction and the target label is doesn't fit the size of the instruction operand.
        /// </exception>
        public int AddMethodBody(
            InstructionEncoder instructionEncoder, 
            int maxStack = 8,
            StandaloneSignatureHandle localVariablesSignature = default(StandaloneSignatureHandle),
            MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals)
        {
            if (unchecked((uint)maxStack) > ushort.MaxValue)
            {
                Throw.ArgumentOutOfRange(nameof(maxStack));
            }

            // The branch fixup code expects the operands of branch instructions in the code builder to be contiguous.
            // That's true when we emit thru InstructionEncoder. Taking it as a parameter instead of separate 
            // code and flow builder parameters ensures they match each other.
            var codeBuilder = instructionEncoder.CodeBuilder;
            var flowBuilder = instructionEncoder.ControlFlowBuilder;

            if (codeBuilder == null)
            {
                Throw.ArgumentNull(nameof(instructionEncoder));
            }

            int exceptionRegionCount = flowBuilder?.ExceptionHandlerCount ?? 0;
            if (!ExceptionRegionEncoder.IsExceptionRegionCountInBounds(exceptionRegionCount))
            {
                Throw.ArgumentOutOfRange(nameof(instructionEncoder), SR.TooManyExceptionRegions);
            }

            int bodyOffset = SerializeHeader(codeBuilder.Count, (ushort)maxStack, exceptionRegionCount, attributes, localVariablesSignature);

            if (flowBuilder?.BranchCount > 0)
            {
                flowBuilder.CopyCodeAndFixupBranches(codeBuilder, Builder);
            }
            else
            {
                codeBuilder.WriteContentTo(Builder);
            }

            flowBuilder?.SerializeExceptionTable(Builder);
            
            return bodyOffset;
        }