示例#1
0
        void CreateContainerStructure()
        {
            List <TryCatch> tryCatchList = new List <TryCatch>();

            foreach (var eh in body.ExceptionHandlers)
            {
                var tryRange     = new Interval(eh.TryStart.Offset, eh.TryEnd != null ? eh.TryEnd.Offset : body.CodeSize);
                var handlerBlock = new BlockContainer();
                handlerBlock.ILRange = new Interval(eh.HandlerStart.Offset, eh.HandlerEnd != null ? eh.HandlerEnd.Offset : body.CodeSize);
                handlerBlock.Blocks.Add(new Block());
                handlerContainers.Add(handlerBlock.ILRange.Start, handlerBlock);

                if (eh.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Fault || eh.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Finally)
                {
                    var tryBlock = new BlockContainer();
                    tryBlock.ILRange = tryRange;
                    if (eh.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Finally)
                    {
                        tryInstructionList.Add(new TryFinally(tryBlock, handlerBlock));
                    }
                    else
                    {
                        tryInstructionList.Add(new TryFault(tryBlock, handlerBlock));
                    }
                    continue;
                }
                //
                var tryCatch = tryCatchList.FirstOrDefault(tc => tc.TryBlock.ILRange == tryRange);
                if (tryCatch == null)
                {
                    var tryBlock = new BlockContainer();
                    tryBlock.ILRange = tryRange;
                    tryCatch         = new TryCatch(tryBlock);
                    tryCatchList.Add(tryCatch);
                    tryInstructionList.Add(tryCatch);
                }

                ILInstruction filter;
                if (eh.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Filter)
                {
                    var filterBlock = new BlockContainer(expectedResultType: StackType.I4);
                    filterBlock.ILRange = new Interval(eh.FilterStart.Offset, eh.HandlerStart.Offset);
                    filterBlock.Blocks.Add(new Block());
                    handlerContainers.Add(filterBlock.ILRange.Start, filterBlock);
                    filter = filterBlock;
                }
                else
                {
                    filter = new LdcI4(1);
                }

                tryCatch.Handlers.Add(new TryCatchHandler(filter, handlerBlock, variableByExceptionHandler[eh]));
            }
            if (tryInstructionList.Count > 0)
            {
                tryInstructionList = tryInstructionList.OrderBy(tc => tc.TryBlock.ILRange.Start).ThenByDescending(tc => tc.TryBlock.ILRange.End).ToList();
                nextTry            = tryInstructionList[0];
            }
        }
示例#2
0
        void CreateContainerStructure()
        {
            List <TryCatch> tryCatchList = new List <TryCatch>();

            foreach (var eh in body.ExceptionRegions)
            {
                var tryRange     = new Interval(eh.TryOffset, eh.TryOffset + eh.TryLength);
                var handlerBlock = new BlockContainer();
                handlerBlock.ILRange = new Interval(eh.HandlerOffset, eh.HandlerOffset + eh.HandlerLength);
                handlerBlock.Blocks.Add(new Block());
                handlerContainers.Add(handlerBlock.ILRange.Start, handlerBlock);

                if (eh.Kind == ExceptionRegionKind.Fault || eh.Kind == ExceptionRegionKind.Finally)
                {
                    var tryBlock = new BlockContainer();
                    tryBlock.ILRange = tryRange;
                    if (eh.Kind == ExceptionRegionKind.Finally)
                    {
                        tryInstructionList.Add(new TryFinally(tryBlock, handlerBlock)
                        {
                            ILRange = tryRange
                        });
                    }
                    else
                    {
                        tryInstructionList.Add(new TryFault(tryBlock, handlerBlock)
                        {
                            ILRange = tryRange
                        });
                    }
                    continue;
                }
                //
                var tryCatch = tryCatchList.FirstOrDefault(tc => tc.TryBlock.ILRange == tryRange);
                if (tryCatch == null)
                {
                    var tryBlock = new BlockContainer();
                    tryBlock.ILRange = tryRange;
                    tryCatch         = new TryCatch(tryBlock);
                    tryCatch.ILRange = tryRange;
                    tryCatchList.Add(tryCatch);
                    tryInstructionList.Add(tryCatch);
                }

                ILInstruction filter;
                if (eh.Kind == System.Reflection.Metadata.ExceptionRegionKind.Filter)
                {
                    var filterBlock = new BlockContainer(expectedResultType: StackType.I4);
                    filterBlock.ILRange = new Interval(eh.FilterOffset, eh.HandlerOffset);
                    filterBlock.Blocks.Add(new Block());
                    handlerContainers.Add(filterBlock.ILRange.Start, filterBlock);
                    filter = filterBlock;
                }
                else
                {
                    filter = new LdcI4(1);
                }

                var handler = new TryCatchHandler(filter, handlerBlock, variableByExceptionHandler[eh]);
                handler.AddILRange(filter.ILRange);
                handler.AddILRange(handlerBlock.ILRange);
                tryCatch.Handlers.Add(handler);
                tryCatch.AddILRange(handler.ILRange);
            }
            if (tryInstructionList.Count > 0)
            {
                tryInstructionList = tryInstructionList.OrderBy(tc => tc.TryBlock.ILRange.Start).ThenByDescending(tc => tc.TryBlock.ILRange.End).ToList();
                nextTry            = tryInstructionList[0];
            }
        }
示例#3
0
        /// <summary>
        /// Transform compound assignments where the return value is not being used,
        /// or where there's an inlined assignment within the setter call.
        ///
        /// Patterns handled:
        /// 1.
        ///   callvirt set_Property(ldloc S_1, binary.op(callvirt get_Property(ldloc S_1), value))
        ///   ==> compound.op.new(callvirt get_Property(ldloc S_1), value)
        /// 2.
        ///   callvirt set_Property(ldloc S_1, stloc v(binary.op(callvirt get_Property(ldloc S_1), value)))
        ///   ==> stloc v(compound.op.new(callvirt get_Property(ldloc S_1), value))
        /// 3.
        ///   stobj(target, binary.op(ldobj(target), ...))
        ///     where target is pure
        ///   => compound.op(target, ...)
        /// </summary>
        /// <remarks>
        /// Called by ExpressionTransforms, or after the inline-assignment transform for setters.
        /// </remarks>
        internal static bool HandleCompoundAssign(ILInstruction compoundStore, StatementTransformContext context)
        {
            if (!context.Settings.MakeAssignmentExpressions || !context.Settings.IntroduceIncrementAndDecrement)
            {
                return(false);
            }
            if (compoundStore is CallInstruction && compoundStore.SlotInfo != Block.InstructionSlot)
            {
                // replacing 'call set_Property' with a compound assignment instruction
                // changes the return value of the expression, so this is only valid on block-level.
                return(false);
            }
            if (!IsCompoundStore(compoundStore, out var targetType, out var setterValue, context.TypeSystem))
            {
                return(false);
            }
            // targetType = The type of the property/field/etc. being stored to.
            // setterValue = The value being stored.
            var storeInSetter = setterValue as StLoc;

            if (storeInSetter != null)
            {
                // We'll move the stloc to top-level:
                // callvirt set_Property(ldloc S_1, stloc v(binary.op(callvirt get_Property(ldloc S_1), value)))
                // ==> stloc v(compound.op.new(callvirt get_Property(ldloc S_1), value))
                setterValue = storeInSetter.Value;
                if (storeInSetter.Variable.Type.IsSmallIntegerType())
                {
                    // 'stloc v' implicitly truncates the value.
                    // Ensure that type of 'v' matches the type of the property:
                    if (storeInSetter.Variable.Type.GetSize() != targetType.GetSize())
                    {
                        return(false);
                    }
                    if (storeInSetter.Variable.Type.GetSign() != targetType.GetSign())
                    {
                        return(false);
                    }
                }
            }
            ILInstruction newInst;

            if (UnwrapSmallIntegerConv(setterValue, out var smallIntConv) is BinaryNumericInstruction binary)
            {
                if (compoundStore is StLoc)
                {
                    // transform local variables only for user-defined operators
                    return(false);
                }
                if (!IsMatchingCompoundLoad(binary.Left, compoundStore, out var target, out var targetKind, out var finalizeMatch, forbiddenVariable: storeInSetter?.Variable))
                {
                    return(false);
                }
                if (!ValidateCompoundAssign(binary, smallIntConv, targetType))
                {
                    return(false);
                }
                context.Step($"Compound assignment (binary.numeric)", compoundStore);
                finalizeMatch?.Invoke(context);
                newInst = new NumericCompoundAssign(
                    binary, target, targetKind, binary.Right,
                    targetType, CompoundEvalMode.EvaluatesToNewValue);
            }
            else if (setterValue is Call operatorCall && operatorCall.Method.IsOperator)
            {
                if (operatorCall.Arguments.Count == 0)
                {
                    return(false);
                }
                if (!IsMatchingCompoundLoad(operatorCall.Arguments[0], compoundStore, out var target, out var targetKind, out var finalizeMatch, forbiddenVariable: storeInSetter?.Variable))
                {
                    return(false);
                }
                ILInstruction rhs;
                if (operatorCall.Arguments.Count == 2)
                {
                    if (CSharp.ExpressionBuilder.GetAssignmentOperatorTypeFromMetadataName(operatorCall.Method.Name) == null)
                    {
                        return(false);
                    }
                    rhs = operatorCall.Arguments[1];
                }
                else if (operatorCall.Arguments.Count == 1)
                {
                    if (!(operatorCall.Method.Name == "op_Increment" || operatorCall.Method.Name == "op_Decrement"))
                    {
                        return(false);
                    }
                    // use a dummy node so that we don't need a dedicated instruction for user-defined unary operator calls
                    rhs = new LdcI4(1);
                }
                else
                {
                    return(false);
                }
                if (operatorCall.IsLifted)
                {
                    return(false);                    // TODO: add tests and think about whether nullables need special considerations
                }
                context.Step($"Compound assignment (user-defined binary)", compoundStore);
                finalizeMatch?.Invoke(context);
                newInst = new UserDefinedCompoundAssign(operatorCall.Method, CompoundEvalMode.EvaluatesToNewValue,
                                                        target, targetKind, rhs);
            }
示例#4
0
 // convert from boolean to integer (or enum)
 return(new ConditionalExpression(
            this.Expression,
            LdcI4(compilation, 1).ConvertTo(targetType, expressionBuilder, checkForOverflow),