Example #1
0
        /// <summary>
        /// Analyzes the tail end (last two instructions) of a block.
        /// </summary>
        /// <remarks>
        /// Sets <c>switchVar</c> and <c>defaultInstruction</c> if they are null,
        /// and adds found sections to <c>sectionLabels</c> and <c>sectionInstructions</c>.
        ///
        /// If the function returns false, <c>sectionLabels</c> and <c>sectionInstructions</c> are unmodified.
        /// </remarks>
        /// <param name="block">The block to analyze.</param>
        /// <param name="inputValues">The possible values of the "interesting" variable
        /// when control flow reaches this block.</param>
        /// <param name="tailOnly">If true, analyze only the tail (last two instructions).
        /// If false, analyze the whole block.</param>
        bool AnalyzeBlock(Block block, LongSet inputValues, bool tailOnly = false)
        {
            if (tailOnly)
            {
                Debug.Assert(block == rootBlock);
                if (block.Instructions.Count < 2)
                {
                    return(false);
                }
            }
            else
            {
                Debug.Assert(switchVar != null);                 // switchVar should always be determined by the top-level call
                if (block.IncomingEdgeCount != 1 || block == rootBlock)
                {
                    return(false);                    // for now, let's only consider if-structures that form a tree
                }
                if (block.Instructions.Count != 2)
                {
                    return(false);
                }
                if (block.Parent != rootBlock.Parent)
                {
                    return(false);                    // all blocks should belong to the same container
                }
            }
            var           inst = block.Instructions[block.Instructions.Count - 2];
            ILInstruction condition, trueInst;
            LongSet       trueValues;

            if (inst.MatchIfInstruction(out condition, out trueInst) &&
                AnalyzeCondition(condition, out trueValues)
                )
            {
                trueValues = trueValues.IntersectWith(inputValues);
                Block trueBlock;
                if (trueInst.MatchBranch(out trueBlock) && AnalyzeBlock(trueBlock, trueValues))
                {
                    // OK, true block was further analyzed.
                    InnerBlocks.Add(trueBlock);
                }
                else
                {
                    // Create switch section for trueInst.
                    AddSection(trueValues, trueInst);
                }
            }
            else if (inst.OpCode == OpCode.SwitchInstruction)
            {
                if (AnalyzeSwitch((SwitchInstruction)inst, inputValues, out trueValues))
                {
                    ContainsILSwitch = true; // OK
                }
                else                         // switch analysis failed (e.g. switchVar mismatch)
                {
                    return(false);
                }
            }
            else                 // unknown inst
            {
                return(false);
            }

            var           remainingValues = inputValues.ExceptWith(trueValues);
            ILInstruction falseInst       = block.Instructions.Last();
            Block         falseBlock;

            if (falseInst.MatchBranch(out falseBlock) && AnalyzeBlock(falseBlock, remainingValues))
            {
                // OK, false block was further analyzed.
                InnerBlocks.Add(falseBlock);
            }
            else
            {
                // Create switch section for falseInst.
                AddSection(remainingValues, falseInst);
            }
            return(true);
        }