private void CreateSwitchConstruct(CFGBlockLogicalConstruct switchBlock, ILogicalConstruct parentConstruct,
            SwitchData switchData, DominatorTree dominatorTree)
        {
            List<KeyValuePair<CFGBlockLogicalConstruct, List<int>>> cfgSuccessorToLabelsMap = GetOrderedCFGSuccessorToLabelsMap(switchData);
            Dictionary<ILogicalConstruct, HashSet<ISingleEntrySubGraph>> validCaseEntryToDominatedNodesMap = GetValidCases(dominatorTree, switchBlock);

            List<CaseLogicalConstruct> orderedCaseConstructs = new List<CaseLogicalConstruct>();
            PairList<List<int>, CFGBlockLogicalConstruct> labelsToCFGSuccessorsList = new PairList<List<int>, CFGBlockLogicalConstruct>();
            foreach (KeyValuePair<CFGBlockLogicalConstruct, List<int>> cfgSuccessorToLabelsPair in cfgSuccessorToLabelsMap)
            {
                ILogicalConstruct successor;
                HashSet<ISingleEntrySubGraph> dominatedNodes;
                if (LogicalFlowUtilities.TryGetParentConstructWithGivenParent(cfgSuccessorToLabelsPair.Key, parentConstruct, out successor) &&
                    validCaseEntryToDominatedNodesMap.TryGetValue(successor, out dominatedNodes))
                {
                    CaseLogicalConstruct newCaseConstruct = new CaseLogicalConstruct(successor);
                    newCaseConstruct.CaseNumbers.AddRange(cfgSuccessorToLabelsPair.Value);
                    newCaseConstruct.Body.UnionWith(dominatedNodes.Cast<ILogicalConstruct>());
                    newCaseConstruct.AttachCaseConstructToGraph();
                    orderedCaseConstructs.Add(newCaseConstruct);
                }
                else
                {
                    labelsToCFGSuccessorsList.Add(cfgSuccessorToLabelsPair.Value, cfgSuccessorToLabelsPair.Key);
                }
            }

            CaseLogicalConstruct defaultCase = null;
            CFGBlockLogicalConstruct defaultCFGSuccessor = GetCFGLogicalConstructFromBlock(switchData.DefaultCase);
            ILogicalConstruct defaultSuccessor;
            HashSet<ISingleEntrySubGraph> defaultCaseNodes;
            if (LogicalFlowUtilities.TryGetParentConstructWithGivenParent(defaultCFGSuccessor, parentConstruct, out defaultSuccessor) &&
                    validCaseEntryToDominatedNodesMap.TryGetValue(defaultSuccessor, out defaultCaseNodes))
            {
                defaultCase = new CaseLogicalConstruct(defaultSuccessor);
                if (HasSuccessors(defaultCaseNodes))
                {
                    defaultCase.Body.UnionWith(defaultCaseNodes.Cast<ILogicalConstruct>());
                }
                defaultCase.AttachCaseConstructToGraph();
            }

            SwitchLogicalConstruct theSwitch = SwitchLogicalConstruct.GroupInSwitchConstruct(switchBlock, orderedCaseConstructs, labelsToCFGSuccessorsList, defaultCase, defaultCFGSuccessor);
            UpdateDominatorTree(dominatorTree, theSwitch);
        }
 private void CreateControllerSwitchData()
 {
     V_0            = this.GetIndexOfLastNonNullElement(this.stateToStartBlock);
     stackVariable6 = V_0 + 1;
     V_0            = stackVariable6;
     V_1            = new InstructionBlock[stackVariable6];
     V_2            = 0;
     while (V_2 < V_0)
     {
         if (!InstructionBlock.op_Equality(this.stateToStartBlock[V_2], null))
         {
             V_1[V_2] = this.stateToStartBlock[V_2];
         }
         else
         {
             V_1[V_2] = this.defaultStateEntry;
         }
         V_2 = V_2 + 1;
     }
     this.switchData = new Telerik.JustDecompiler.Cil.SwitchData(null, this.defaultStateEntry, V_1);
     return;
 }
 public StateMachineCFGCleaner(ControlFlowGraph theCFG, SwitchData controllerSwitchData, InstructionBlock newEntryBlock)
 {
     this.theCFG = theCFG;
     this.controllerSwitchData = controllerSwitchData;
     this.newEntryBlock = newEntryBlock;
 }
        /// <summary>
        /// Process each switch block to determine which cases lead to try/finally constructs.
        /// </summary>
        /// <remarks>
        /// E.g.: If the cases from 3 to 5 lead to the same try/finally construct then there is a try/finally construct in the MoveNext method
        /// that covers states 3, 4 and 5.
        /// </remarks>
        /// <param name="switchBlockInfo"></param>
        private bool DetermineExceptionHandlingIntervalsFromSwitchData(SwitchData switchBlockInfo)
        {
            //Since the first try/finally that this switch covers can start at state 20, the complier will optimize this by subtracting 20 from the value of
            //the state field.
            int stateOffset = 0;
            Instruction currentInstruction = switchBlockInfo.SwitchBlock.Last.Previous;
            if (currentInstruction.OpCode.Code == Code.Sub)
            {
                currentInstruction = currentInstruction.Previous;
                if (!StateMachineUtilities.TryGetOperandOfLdc(currentInstruction, out stateOffset))
                {
                    return false;
                }

                currentInstruction = currentInstruction.Previous;
            }

            //The switch instruction block usually looks like this:
            //
            //ldarg.0 <- this
            //ldfld stateField
            //stloc.0
            //ldloc.0                  <- currentInstruction
            //(ldc.i4 stateOffset)
            //(sub)
            //switch ....
            currentInstruction = currentInstruction.Previous.Previous;
            if (currentInstruction.OpCode.Code != Code.Ldfld || !(currentInstruction.Operand is FieldReference) ||
                !CheckAndSaveStateField(currentInstruction.Operand as FieldReference))
            {
                //sanity check - the state field used by the Dispose method should be the same as the field used by the MoveNext method
                return false;
            }

            //The algorithm works with the presumption that a try/finally construct contains a consecutive sequence of states.
            InstructionBlock[] orderedCases = switchBlockInfo.OrderedCasesArray;
            InstructionBlock currentBlock = null;
            int intervalStart = -1;
            int intervalEnd = -1;
            ExceptionHandler exceptionHandler = null;
            for (int i = 0; i < orderedCases.Length; i++)
            {
                InstructionBlock currentCase = GetActualCase(orderedCases[i]);

                if (currentBlock != null && currentCase == currentBlock) //Current block will be null, if we still haven't found an exception handler.
                {
                    intervalEnd = i + stateOffset;
                    continue;
                }

                ExceptionHandler theHandler;
                if (!TryGetExceptionHandler(currentCase, out theHandler))
                {
                    //There are cases where a state is never reached (i.e. the state field is never assigned this state number).
                    //This can create holes in the exception handlers, but since the states are never reached we can add them to the handler.
                    //(We work with the assumption that if state 3 and state 6 are handled by the same try/finally construct and 4 and 5 are not handled by
                    //any exception handler, then 4 and 5 are unreachable. True in general, but obfuscation can break this assumption.)
                    continue;
                }

                //We've found an exception handler.

                if (currentBlock != null) //If currentBlock != null, then currentBlock != currentCase. This means that we have found a new exception
                //handler, so we must store the data for the old one.
                {
                    if (!TryCreateYieldExceptionHandler(intervalStart, intervalEnd, exceptionHandler))
                    {
                        return false;
                    }
                }
                else //Otherwise this is the first handler found for the switch block.
                {
                    currentBlock = currentCase;
                }

                intervalStart = i + stateOffset;
                exceptionHandler = theHandler;
            }

            return currentBlock == null ||
                TryCreateYieldExceptionHandler(intervalStart, intervalEnd, exceptionHandler); //Store the data for the last found exception handler.
        }
        /// <summary>
        /// Creates the controller switch data using the information gathered during the traversal of the state controller blocks.
        /// </summary>
        private void CreateControllerSwitchData()
        {
            int index = GetIndexOfLastNonNullElement(stateToStartBlock);
            InstructionBlock[] finalCasesArray = new InstructionBlock[++index];
            //Trim the excess elements of the cases array.
            for (int i = 0; i < index; i++)
            {
                if (stateToStartBlock[i] == null)
                {
                    finalCasesArray[i] = defaultStateEntry;
                }
                else
                {
                    finalCasesArray[i] = stateToStartBlock[i];
                }
            }

            this.switchData = new SwitchData(null, defaultStateEntry, finalCasesArray);
        }
 public YieldStateMachineControlFlowRebuilder(MethodSpecificContext moveNextMethodContext, SwitchData controllerSwitchData, FieldDefinition stateField)
 {
     this.moveNextMethodContext = moveNextMethodContext;
     this.switchData = controllerSwitchData;
     this.stateField = stateField;
 }
        /// <summary>
        /// Process each switch block to determine which cases lead to try/finally constructs.
        /// </summary>
        /// <param name="switchBlockInfo"></param>
        private bool DetermineExceptionHandlingStatesFromSwitchData(SwitchData switchBlockInfo)
        {
            //Since the first try/finally that this switch covers can start at state 20, the complier will optimize this by subtracting 20 from the value of
            //the state field.
            int stateOffset = 0;
            Instruction currentInstruction = switchBlockInfo.SwitchBlock.Last.Previous;
            if (currentInstruction.OpCode.Code == Code.Sub)
            {
                currentInstruction = currentInstruction.Previous;
                if (!StateMachineUtilities.TryGetOperandOfLdc(currentInstruction, out stateOffset))
                {
                    return false;
                }

                currentInstruction = currentInstruction.Previous;
            }

            InstructionBlock[] orderedCases = switchBlockInfo.OrderedCasesArray;
            for (int i = 0; i < orderedCases.Length; i++)
            {
                InstructionBlock currentCase = GetActualCase(orderedCases[i]);

                ExceptionHandler theHandler;
                if (!TryGetExceptionHandler(currentCase, out theHandler))
                {
                    continue;
                }

                //We've found an exception handler.

                if (!this.handlerToStatesMap.ContainsKey(theHandler))
                {
                    this.handlerToStatesMap.Add(theHandler, new HashSet<int>());
                }

                this.handlerToStatesMap[theHandler].Add(i + stateOffset);
            }

            return true;
        }
        private PairList<CFGBlockLogicalConstruct, List<int>> GetOrderedCFGSuccessorToLabelsMap(SwitchData switchData)
        {
            //Ugly but effective. Sorry
            PairList<CFGBlockLogicalConstruct, List<int>> result = new PairList<CFGBlockLogicalConstruct, List<int>>();
            Dictionary<InstructionBlock, KeyValuePair<int, List<int>>> blockSuccessorToResultPositionMap =
                new Dictionary<InstructionBlock, KeyValuePair<int, List<int>>>();

            for (int i = 0; i < switchData.OrderedCasesArray.Length; i++)
            {
                InstructionBlock instructionBlock = switchData.OrderedCasesArray[i];
                if (instructionBlock != switchData.DefaultCase)
                {
                    KeyValuePair<int, List<int>> positionToLabelListPair;
                    if (!blockSuccessorToResultPositionMap.TryGetValue(instructionBlock, out positionToLabelListPair))
                    {
                        positionToLabelListPair = new KeyValuePair<int, List<int>>(result.Count, new List<int>());

                        result.Add(GetCFGLogicalConstructFromBlock(instructionBlock), positionToLabelListPair.Value);

                        blockSuccessorToResultPositionMap.Add(instructionBlock, positionToLabelListPair);
                    }
                    positionToLabelListPair.Value.Add(i);
                }
            }

            return result;
        }