/// <summary> /// Marks the predecessors of this block as yield return. Also adds this block to the set of nodes that are to be removed. /// </summary> /// <remarks> /// If a predecessor of the specified block is a block with a single unconditional branch instruction, then this method is /// recursively called for that predecessor. /// </remarks> /// <param name="theBlock"></param> private bool MarkPredecessorsAsYieldReturns(InstructionBlock theBlock) { toBeRemoved.Add(theBlock); HashSet <InstructionBlock> predecessors = new HashSet <InstructionBlock>(theBlock.Predecessors); foreach (InstructionBlock predecessor in predecessors) { if (predecessor.Last == predecessor.First) { if (StateMachineUtilities.IsUnconditionalBranch(predecessor.Last) && MarkPredecessorsAsYieldReturns(predecessor)) { continue; } else { //throw new Exception("Illegal block"); return(false); } } if (!TryAddToYieldReturningBlocks(predecessor)) { return(false); } } return(true); }
/// <summary> /// Marks the predecessors, of the specifed instruction block, that set the return flag variable to true, as yield returns. /// </summary> /// <remarks> /// If a predecessor is a block that contains a single unconditional branch instruction then we recursively call the method for that /// predecessor and we mark it for removal. /// This means that the block, that we initially call this method for, will not be removed and will be left to be marked as an yield break. /// </remarks> /// <param name="theBlock"></param> private bool MarkTrueReturningPredecessorsAsYieldReturn(InstructionBlock theBlock) { HashSet <InstructionBlock> predecessors = new HashSet <InstructionBlock>(theBlock.Predecessors); foreach (InstructionBlock predecessor in predecessors) { if (predecessor.Last == predecessor.First) { if (StateMachineUtilities.IsUnconditionalBranch(predecessor.Last)) { toBeRemoved.Add(predecessor); if (!MarkTrueReturningPredecessorsAsYieldReturn(predecessor)) { return(false); } continue; } else { return(false); } } VariableReference flagVarReference = null; Instruction lastInstruction = predecessor.Last; if (StateMachineUtilities.IsUnconditionalBranch(lastInstruction)) { lastInstruction = lastInstruction.Previous; } int returnValue; if (TryGetVariableFromInstruction(lastInstruction, out flagVarReference) && CheckAndSaveReturnFlagVariable(flagVarReference) && StateMachineUtilities.TryGetOperandOfLdc(lastInstruction.Previous, out returnValue)) { if (returnValue == 1) { if (!TryAddToYieldReturningBlocks(predecessor)) { return(false); } } else if (returnValue != 0) { return(false); } } else { return(false); } } return(true); }
/// <summary> /// Checks if the given block is block that contains only Finally method invocation. This pattern is brought by the new C#6.0 compiler. /// </summary> private bool IsFinallyMethodInvocationBlock(InstructionBlock block) { // The pattern is like so: // ldarg.0 // call instance void ... (the finally method) // nop <- could be missing // leave.s ... Instruction current = block.First; if (current.OpCode.Code != Code.Ldarg_0) { return(false); } current = current.Next; if (current.OpCode.Code != Code.Call) { return(false); } Instruction callInstruction = current; current = current.Next; if (current.OpCode.Code == Code.Nop) { current = current.Next; } if (!StateMachineUtilities.IsUnconditionalBranch(current)) { return(false); } if (block.Last != current) { return(false); } MethodReference finallyMethod = callInstruction.Operand as MethodReference; if (finallyMethod == null) { return(false); } if (!finallyMethod.Name.StartsWith("<>m__Finally")) { return(false); } return(true); }
private bool IsFalseReturnBlock(InstructionBlock theBlock) { V_0 = theBlock.get_First(); if (V_0.get_OpCode().get_Code() != 22 || (object)V_0 == (object)theBlock.get_Last()) { return(false); } V_0 = V_0.get_Next(); if (!this.TryGetVariableFromInstruction(V_0, out V_1) || (object)V_0 == (object)theBlock.get_Last() || !this.CheckAndSaveReturnFlagVariable(V_1)) { return(false); } V_0 = V_0.get_Next(); return(StateMachineUtilities.IsUnconditionalBranch(V_0)); }
/// <summary> /// Checks whether the block sets the returnFlag variable to false. /// </summary> /// <param name="theBlock"></param> /// <returns></returns> private bool IsFalseReturnBlock(InstructionBlock theBlock) { Instruction currentInstruction = theBlock.First; if (currentInstruction.OpCode.Code != Code.Ldc_I4_0 || currentInstruction == theBlock.Last) { return(false); } currentInstruction = currentInstruction.Next; VariableReference retFlagVariable; if (!TryGetVariableFromInstruction(currentInstruction, out retFlagVariable) || currentInstruction == theBlock.Last || !CheckAndSaveReturnFlagVariable(retFlagVariable)) { return(false); } currentInstruction = currentInstruction.Next; return(StateMachineUtilities.IsUnconditionalBranch(currentInstruction)); }
private bool MarkPredecessorsAsYieldReturns(InstructionBlock theBlock) { dummyVar0 = this.toBeRemoved.Add(theBlock); V_0 = (new HashSet <InstructionBlock>(theBlock.get_Predecessors())).GetEnumerator(); try { while (V_0.MoveNext()) { V_1 = V_0.get_Current(); if ((object)V_1.get_Last() != (object)V_1.get_First()) { if (this.TryAddToYieldReturningBlocks(V_1)) { continue; } V_2 = false; goto Label1; } else { if (StateMachineUtilities.IsUnconditionalBranch(V_1.get_Last()) && this.MarkPredecessorsAsYieldReturns(V_1)) { continue; } V_2 = false; goto Label1; } } goto Label0; } finally { ((IDisposable)V_0).Dispose(); } Label1: return(V_2); Label0: return(true); }
private bool IsFinallyMethodInvocationBlock(InstructionBlock block) { V_0 = block.get_First(); if (V_0.get_OpCode().get_Code() != 2) { return(false); } V_0 = V_0.get_Next(); if (V_0.get_OpCode().get_Code() != 39) { return(false); } V_1 = V_0; V_0 = V_0.get_Next(); if (V_0.get_OpCode().get_Code() == null) { V_0 = V_0.get_Next(); } if (!StateMachineUtilities.IsUnconditionalBranch(V_0)) { return(false); } if ((object)block.get_Last() != (object)V_0) { return(false); } V_2 = V_1.get_Operand() as MethodReference; if (V_2 == null) { return(false); } if (!V_2.get_Name().StartsWith("<>m__Finally")) { return(false); } return(true); }
/// <summary> /// Checks whether the given block contains only an unconditional branch instruction. /// </summary> /// <param name="theBlock"></param> /// <returns></returns> protected virtual bool IsUnconditionalBranchBlock(InstructionBlock theBlock) { return(StateMachineUtilities.IsUnconditionalBranch(theBlock.First)); }
private bool MarkTrueReturningPredecessorsAsYieldReturn(InstructionBlock theBlock) { V_0 = (new HashSet <InstructionBlock>(theBlock.get_Predecessors())).GetEnumerator(); try { while (V_0.MoveNext()) { V_1 = V_0.get_Current(); if ((object)V_1.get_Last() != (object)V_1.get_First()) { V_2 = null; V_3 = V_1.get_Last(); if (StateMachineUtilities.IsUnconditionalBranch(V_3)) { V_3 = V_3.get_Previous(); } if (!this.IsFinallyMethodInvocationBlock(V_1)) { if (!this.TryGetVariableFromInstruction(V_3, out V_2) || !this.CheckAndSaveReturnFlagVariable(V_2) || !StateMachineUtilities.TryGetOperandOfLdc(V_3.get_Previous(), out V_4)) { V_5 = false; goto Label1; } else { if (V_4 != 1) { if (V_4 == 0) { continue; } V_5 = false; goto Label1; } else { if (this.TryAddToYieldReturningBlocks(V_1)) { continue; } V_5 = false; goto Label1; } } } else { if (this.MarkTrueReturningPredecessorsAsYieldReturn(V_1)) { continue; } V_5 = false; goto Label1; } } else { if (!StateMachineUtilities.IsUnconditionalBranch(V_1.get_Last())) { V_5 = false; goto Label1; } else { dummyVar0 = this.toBeRemoved.Add(V_1); if (this.MarkTrueReturningPredecessorsAsYieldReturn(V_1)) { continue; } V_5 = false; goto Label1; } } } goto Label0; } finally { ((IDisposable)V_0).Dispose(); } Label1: return(V_5); Label0: return(true); }