Пример #1
0
        /// <summary>
        /// Finds the position to inline to.
        /// </summary>
        /// <returns>true = found; false = cannot continue search; null = not found</returns>
        internal static FindResult FindLoadInNext(ILInstruction expr, ILVariable v, ILInstruction expressionBeingMoved, InliningOptions options)
        {
            if (expr == null)
            {
                return(FindResult.Stop);
            }
            if (expr.MatchLdLoc(v) || expr.MatchLdLoca(v))
            {
                // Match found, we can inline
                if (expr.SlotInfo == StObj.TargetSlot && !((StObj)expr.Parent).CanInlineIntoTargetSlot(expressionBeingMoved))
                {
                    // special case: the StObj.TargetSlot does not accept some kinds of expressions
                    return(FindResult.Stop);
                }
                return(FindResult.Found(expr));
            }
            else if (expr is Block block)
            {
                // Inlining into inline-blocks?
                switch (block.Kind)
                {
                case BlockKind.ArrayInitializer:
                case BlockKind.CollectionInitializer:
                case BlockKind.ObjectInitializer:
                case BlockKind.CallInlineAssign:
                    // Allow inlining into the first instruction of the block
                    if (block.Instructions.Count == 0)
                    {
                        return(FindResult.Stop);
                    }
                    return(NoContinue(FindLoadInNext(block.Instructions[0], v, expressionBeingMoved, options)));

                // If FindLoadInNext() returns null, we still can't continue searching
                // because we can't inline over the remainder of the block.
                case BlockKind.CallWithNamedArgs:
                    return(NamedArgumentTransform.CanExtendNamedArgument(block, v, expressionBeingMoved));

                default:
                    return(FindResult.Stop);
                }
            }
            else if (expr is BlockContainer container && container.EntryPoint.IncomingEdgeCount == 1)
            {
                // Possibly a switch-container, allow inlining into the switch instruction:
                return(NoContinue(FindLoadInNext(container.EntryPoint.Instructions[0], v, expressionBeingMoved, options)));
                // If FindLoadInNext() returns null, we still can't continue searching
                // because we can't inline over the remainder of the blockcontainer.
            }
Пример #2
0
        /// <summary>
        /// Finds the position to inline to.
        /// </summary>
        /// <returns>true = found; false = cannot continue search; null = not found</returns>
        internal static FindResult FindLoadInNext(ILInstruction expr, ILVariable v, ILInstruction expressionBeingMoved, InliningOptions options)
        {
            if (expr == null)
            {
                return(FindResult.Stop);
            }
            if (expr.MatchLdLoc(v) || expr.MatchLdLoca(v))
            {
                // Match found, we can inline
                if (expr.SlotInfo == StObj.TargetSlot && !((StObj)expr.Parent).CanInlineIntoTargetSlot(expressionBeingMoved))
                {
                    if ((options & InliningOptions.AllowChangingOrderOfEvaluationForExceptions) != 0)
                    {
                        // Intentionally change code semantics so that we can avoid a ref local
                        if (expressionBeingMoved is LdFlda ldflda)
                        {
                            ldflda.DelayExceptions = true;
                        }
                        else if (expressionBeingMoved is LdElema ldelema)
                        {
                            ldelema.DelayExceptions = true;
                        }
                    }
                    else
                    {
                        // special case: the StObj.TargetSlot does not accept some kinds of expressions
                        return(FindResult.Stop);
                    }
                }
                return(FindResult.Found(expr));
            }
            else if (expr is Block block)
            {
                // Inlining into inline-blocks?
                switch (block.Kind)
                {
                case BlockKind.ControlFlow when block.Parent is BlockContainer:
                case BlockKind.ArrayInitializer:
                case BlockKind.CollectionInitializer:
                case BlockKind.ObjectInitializer:
                case BlockKind.CallInlineAssign:
                    // Allow inlining into the first instruction of the block
                    if (block.Instructions.Count == 0)
                    {
                        return(FindResult.Stop);
                    }
                    return(NoContinue(FindLoadInNext(block.Instructions[0], v, expressionBeingMoved, options)));

                // If FindLoadInNext() returns null, we still can't continue searching
                // because we can't inline over the remainder of the block.
                case BlockKind.CallWithNamedArgs:
                    return(NamedArgumentTransform.CanExtendNamedArgument(block, v, expressionBeingMoved));

                default:
                    return(FindResult.Stop);
                }
            }
            else if (options.HasFlag(InliningOptions.FindDeconstruction) && expr is DeconstructInstruction di)
            {
                return(FindResult.Deconstruction(di));
            }
            foreach (var child in expr.Children)
            {
                if (!expr.CanInlineIntoSlot(child.ChildIndex, expressionBeingMoved))
                {
                    return(FindResult.Stop);
                }

                // Recursively try to find the load instruction
                FindResult r = FindLoadInNext(child, v, expressionBeingMoved, options);
                if (r.Type != FindResultType.Continue)
                {
                    if (r.Type == FindResultType.Stop && (options & InliningOptions.IntroduceNamedArguments) != 0 && expr is CallInstruction call)
                    {
                        return(NamedArgumentTransform.CanIntroduceNamedArgument(call, child, v, expressionBeingMoved));
                    }
                    return(r);
                }
            }
            if (IsSafeForInlineOver(expr, expressionBeingMoved))
            {
                return(FindResult.Continue);                // continue searching
            }
            else
            {
                return(FindResult.Stop);                // abort, inlining not possible
            }
        }