void ComputeInstructionData(IDictionary visited, int stackHeight, InstructionBlock block) { if (visited.Contains(block)) { return; } visited.Add(block, block); foreach (Instruction instruction in block) { stackHeight = ComputeInstructionData(stackHeight, instruction); } foreach (InstructionBlock successor in block.Successors) { ComputeInstructionData(visited, stackHeight, successor); } }
static InstructionBlock GetThen (InstructionBlock block) { return block.Successors [0]; }
void MarkProcessed (InstructionBlock block) { _processed [block] = block; }
static bool IsFalse (InstructionBlock block) { return block.FirstInstruction == block.LastInstruction && block.FirstInstruction.OpCode.Value == OpCodes.Ldc_I4_0.Value; }
void ProcessNestedExpression (InstructionBlock block) { switch (block.Successors.Length) { case 1: BuildExpression (block); break; case 2: ProcessLogicalExpressionBlock (block); break; default: throw new ArgumentException ("block"); } }
void ProcessNotAnd (InstructionBlock block) { BuildNegateExpression (block); ProcessNestedExpression (GetElse (block)); _expressionDecompiler.PushBinaryExpression (BinaryOperator.LogicalAnd); }
static ExpressionPattern DetectExpressionPattern (InstructionBlock block) { InstructionBlock then = GetThen (block); if (IsTrue (then)) return ExpressionPattern.SimpleOr; if (IsFalse (then)) return ExpressionPattern.SimpleNotAnd; // the following flow graph patterns are described in // Decompilation of .NET Bytecode, Computer Science Tripos Part II // Trinity Hall, May 13, 2004 // Fig. 3.10 on pg. 43 // pattern 4: !x && y if (GetElse (GetElse (block)) == then) return ExpressionPattern.NestedNotAnd; return ExpressionPattern.Unknown; }
void ProcessSimpleBlock (InstructionBlock block) { foreach (Instruction instruction in block) { _expressionDecompiler.Visit (instruction); if (0 == GetStackAfter (instruction)) { CreateActionBlock (instruction); _current = instruction.Next; } } }
void ConnectBlock (InstructionBlock block) { if (block.LastInstruction == null) throw new ApplicationException ("Undelimited block at offset " + block.FirstInstruction.Offset); Instruction instruction = block.LastInstruction; switch (instruction.OpCode.FlowControl) { case FlowControl.Branch: case FlowControl.Cond_Branch: { if (HasMultipleBranches (instruction)) { InstructionBlock [] blocks = GetBranchTargetsBlocks (instruction); if (instruction.Next != null) blocks = AddBlock (GetBlock (instruction.Next), blocks); block.SetSuccessors (blocks); break; } InstructionBlock target = GetBranchTargetBlock (instruction); if (instruction.OpCode.FlowControl == FlowControl.Cond_Branch && instruction.Next != null) block.SetSuccessors (new InstructionBlock [] { target, GetBlock (instruction.Next) }); else block.SetSuccessors (new InstructionBlock [] { target }); break; } case FlowControl.Call: case FlowControl.Next: if (null != instruction.Next) block.SetSuccessors (new InstructionBlock [] { GetBlock (instruction.Next) }); break; case FlowControl.Return: break; default: throw new ApplicationException ( string.Format ("Unhandled instruction flow behavior {0}: {1}", instruction.OpCode.FlowControl, Formatter.FormatInstruction (instruction))); } }
void ComputeInstructionData (IDictionary visited, int stackHeight, InstructionBlock block) { if (visited.Contains (block)) return; visited.Add (block, block); foreach (Instruction instruction in block) { stackHeight = ComputeInstructionData (stackHeight, instruction); } foreach (InstructionBlock successor in block.Successors) { ComputeInstructionData (visited, stackHeight, successor); } }
void MarkBlockStart (Instruction instruction) { InstructionBlock block = GetBlock (instruction); if (null != block) return; block = new InstructionBlock (instruction); RegisterBlock (block); }
void RegisterBlock(InstructionBlock block) { _blocks.Add(block.FirstInstruction.Offset, block); }
void MarkProcessed (InstructionBlock block) { _processed.Add (block); }
/// <summary> /// Checks if the subgraph starting at block represents /// a logical expression. /// </summary> /// <param name="block"></param> /// <returns></returns> bool IsLogicalExpression (InstructionBlock block) { return IsLogicalExpression (new HashSet<InstructionBlock> (), block); }
InstructionBlock [] ToArray (InstructionBlock [] blocks) { _blocks.Values.CopyTo (blocks, 0); Array.Sort (blocks); return blocks; }
static InstructionBlock [] AddBlock (InstructionBlock block, InstructionBlock [] blocks) { InstructionBlock [] result = new InstructionBlock [blocks.Length + 1]; Array.Copy (blocks, result, blocks.Length); result [result.Length - 1] = block; return result; }
bool IsLogicalExpression (Hashtable visited, InstructionBlock block) { if (visited.Contains (block)) return false; visited.Add (block, block); foreach (InstructionBlock successor in block.Successors) { if (GetStackAfter (successor.LastInstruction) > 0) return true; if (IsLogicalExpression (visited, successor)) return true; } return false; }
InstructionBlock [] GetBranchTargetsBlocks (Instruction instruction) { Instruction [] targets = GetBranchTargets (instruction); InstructionBlock [] blocks = new InstructionBlock [targets.Length]; for (int i = 0; i < targets.Length; i++) blocks [i] = GetBlock (targets [i]); return blocks; }
void ProcessLogicalExpressionBlock (InstructionBlock block) { switch (DetectExpressionPattern (block)) { case ExpressionPattern.SimpleOr: ProcessOr (block); break; case ExpressionPattern.SimpleNotAnd: ProcessNotAnd (block); break; case ExpressionPattern.NestedNotAnd: ProcessNestedNotAnd (block); break; default: throw new ArgumentException ("Unknown expression pattern starting at " + Formatter.FormatInstruction (block.FirstInstruction), "block"); } MarkProcessed (block.Successors); }
void RegisterBlock (InstructionBlock block) { _blocks.Add (block.FirstInstruction.Offset, block); }
void ProcessOr (InstructionBlock block) { BuildExpression (block); ProcessNestedExpression (GetElse (block)); _expressionDecompiler.PushBinaryExpression (BinaryOperator.LogicalOr); }
internal void SetSuccessors (InstructionBlock [] successors) { _successors = successors; }
void BuildNegateExpression (InstructionBlock block) { BuildExpression (block); _expressionDecompiler.Negate (); }
private static int GetBlockId(ControlFlowGraph cfg, InstructionBlock block) { return ((IList) cfg.Blocks).IndexOf (block) + 1; }
void BuildExpression (InstructionBlock block) { if (WasProcessed (block)) return; foreach (Instruction instruction in block) { _expressionDecompiler.Visit (instruction); } MarkProcessed (block); }
void ProcessBlock (InstructionBlock block) { switch (block.Successors.Length) { case 0: case 1: ProcessSimpleBlock (block); break; case 2: ProcessTwoWayBlock (block); break; default: throw new ArgumentException ("n-way block not supported", "block"); } MarkProcessed (block); }
void MarkProcessed (InstructionBlock [] blocks) { foreach (InstructionBlock block in blocks) { MarkProcessed (block); } }
void ProcessTwoWayBlock (InstructionBlock block) { if (IsLogicalExpression (block)) { ProcessLogicalExpressionBlock (block); } else { ProcessSimpleBlock (block); } }
bool WasProcessed (InstructionBlock block) { return _processed.Contains (block); }
/// <summary> /// Checks if the subgraph starting at block represents /// a logical expression. /// </summary> /// <param name="block"></param> /// <returns></returns> bool IsLogicalExpression (InstructionBlock block) { return IsLogicalExpression (new Hashtable (), block); }
static InstructionBlock GetElse (InstructionBlock block) { return block.Successors [1]; }
public ControlFlowGraph (MethodBody body, InstructionBlock [] blocks, IDictionary instructionData) { _body = body; _blocks = blocks; _data = instructionData; }