protected override ICode VisitCil(StmtCil s) { var endStackSize = this.StackSizeAnalysis(s.Insts, s.StartStackSize); s.EndStackSize = endStackSize; var conts = VisitorFindContinuations.Get(s.EndCil); Action<Stmt, int> setStackSize = null; setStackSize = (stmt, stackSize) => { // Set all try and catch stacksizes recursively, to handle multiple trys start on the same instruction switch (stmt.StmtType) { case Stmt.NodeType.Cil: ((StmtCil)stmt).StartStackSize = stackSize; return; case Stmt.NodeType.Try: var stmtTry = (StmtTry)stmt; setStackSize(stmtTry.Try, stackSize); if (stmtTry.Catches != null) { setStackSize(stmtTry.Catches.First().Stmt, 1); } // 'Finally' stack sizes do not need setting, as they will have defaulted to 0 // and this will always be correct return; case Stmt.NodeType.Return: // do nothing return; default: throw new NotSupportedException("Should not be seeing: " + stmt.StmtType); } }; foreach (var cont in conts) { setStackSize(cont.To, endStackSize); } return base.VisitCil(s); }
public DebugView(StmtCil s) { this.Method = s.Ctx.MRef; this.Insts = s.Insts; this.EndCil = s.EndCil; this.StartStackSize = s.StartStackSize; this.EndStackSize = s.EndStackSize; }
public Stmt Create() { var mDef = this.ctx.MRef.Resolve(); if (!mDef.HasBody) { throw new ArgumentException("Method has no body, cannot create AST"); } var body = mDef.Body; // Pre-calculate all method block starts this.methodBlockStarts = body.Instructions .SelectMany(x => { switch (x.OpCode.FlowControl) { case FlowControl.Cond_Branch: case FlowControl.Branch: if (x.OpCode.Code == Code.Switch) { return(((Instruction[])x.Operand).Concat(x.Next)); } else { return(new[] { (Instruction)x.Operand, x.Next }); } case FlowControl.Throw: case FlowControl.Return: return(new[] { x.Next }); default: return(Enumerable.Empty <Instruction>()); } }) .Concat(body.ExceptionHandlers.SelectMany(x => new[] { x.TryStart, x.TryEnd, x.HandlerStart, x.HandlerEnd })) .Concat(body.Instructions.First()) .Where(x => x != null) .Distinct() .OrderBy(x => x.Offset) .ToArray(); // Create all method blocks this.CreatePart(body.Instructions, body.ExceptionHandlers); // Map continuations and try statements // Must continue to outermost Try statement, if one exists, rather than directly to the first CIL block foreach (var mappable in this.mappable) { mappable.Map(this.blockMap); } var stmt0 = this.blockMap[body.Instructions.First()].First(); var vStackSize = new StackSizeVisitor(); vStackSize.Visit(stmt0); // Create entry block, and return it var entryBlock = new StmtCil(this.ctx, null, new StmtContinuation(this.ctx, stmt0, false), StmtCil.SpecialBlock.Start); return(entryBlock); }
protected override ICode VisitCil(StmtCil s) { var bsi = this.blockStartInfos[s]; var stack = new Stack <Expr>(bsi.Stack.Reverse()); var locals = bsi.Locals.Cast <Expr>().ToArray(); var args = bsi.Args.Cast <Expr>().ToArray(); var orgStack = stack.ToArray(); var orgLocals = locals.ToArray(); var orgArgs = args.ToArray(); var cil = new CilProcessor(this.ctx, stack, locals, args, this.instResults); var stmts = new List <Stmt>(); switch (s.BlockType) { case StmtCil.SpecialBlock.Normal: foreach (var inst in s.Insts) { var stmt = cil.Process(inst); if (stmt != null) { stmts.Add(stmt); } } break; case StmtCil.SpecialBlock.Start: // Do nothing break; case StmtCil.SpecialBlock.End: stmts.Add(cil.ProcessReturn()); break; default: throw new InvalidOperationException("Invalid block type: " + s.BlockType); } this.stmtVarsChanged.Add(s, new StmtVarChanged { Stack = stack.Zip(orgStack, (a, b) => a == b).ToArray(), Locals = locals.Zip(orgLocals, (a, b) => a == b).ToArray(), Args = args.Zip(orgArgs, (a, b) => a == b).ToArray(), }); // Merge phi's var continuations = VisitorFindContinuations.Get(s); foreach (var continuation in continuations) { this.CreateOrMergeBsi(continuation.To, stack.ToArray(), locals, args); } // End var next = (Stmt)this.Visit(s.EndCil); stmts.Add(next); return(new StmtBlock(this.ctx, stmts)); }
protected virtual ICode VisitCil(StmtCil s) { this.ThrowOnNoOverride(); var endCil = (Stmt)this.Visit(s.EndCil); if (endCil != s.EndCil) { return(new StmtCil(s.Ctx, s.Insts, endCil) { StartStackSize = s.StartStackSize, EndStackSize = s.EndStackSize, }); } else { return(s); } }
protected override ICode VisitCil(StmtCil s) { var endStackSize = this.StackSizeAnalysis(s.Insts, s.StartStackSize); s.EndStackSize = endStackSize; var conts = VisitorFindContinuations.Get(s.EndCil); Action <Stmt, int> setStackSize = null; setStackSize = (stmt, stackSize) => { // Set all try and catch stacksizes recursively, to handle multiple trys start on the same instruction switch (stmt.StmtType) { case Stmt.NodeType.Cil: ((StmtCil)stmt).StartStackSize = stackSize; return; case Stmt.NodeType.Try: var stmtTry = (StmtTry)stmt; setStackSize(stmtTry.Try, stackSize); if (stmtTry.Catches != null) { setStackSize(stmtTry.Catches.First().Stmt, 1); } // 'Finally' stack sizes do not need setting, as they will have defaulted to 0 // and this will always be correct return; case Stmt.NodeType.Return: // do nothing return; default: throw new NotSupportedException("Should not be seeing: " + stmt.StmtType); } }; foreach (var cont in conts) { setStackSize(cont.To, endStackSize); } return(base.VisitCil(s)); }
protected override ICode VisitCil(StmtCil s) { var bsi = this.blockStartInfos[s]; var stack = new Stack<Expr>(bsi.Stack.Reverse()); var locals = bsi.Locals.Cast<Expr>().ToArray(); var args = bsi.Args.Cast<Expr>().ToArray(); var orgStack = stack.ToArray(); var orgLocals = locals.ToArray(); var orgArgs = args.ToArray(); var cil = new CilProcessor(this.ctx, stack, locals, args, this.instResults); var stmts = new List<Stmt>(); switch (s.BlockType) { case StmtCil.SpecialBlock.Normal: foreach (var inst in s.Insts) { var stmt = cil.Process(inst); if (stmt != null) { stmts.Add(stmt); } } break; case StmtCil.SpecialBlock.Start: // Do nothing break; case StmtCil.SpecialBlock.End: stmts.Add(cil.ProcessReturn()); break; default: throw new InvalidOperationException("Invalid block type: " + s.BlockType); } this.stmtVarsChanged.Add(s, new StmtVarChanged { Stack = stack.Zip(orgStack, (a, b) => a == b).ToArray(), Locals = locals.Zip(orgLocals, (a, b) => a == b).ToArray(), Args = args.Zip(orgArgs, (a, b) => a == b).ToArray(), }); // Merge phi's var continuations = VisitorFindContinuations.Get(s); foreach (var continuation in continuations) { this.CreateOrMergeBsi(continuation.To, stack.ToArray(), locals, args); } // End var next = (Stmt)this.Visit(s.EndCil); stmts.Add(next); return new StmtBlock(this.ctx, stmts); }
private void BuildBlock(IEnumerable <Instruction> insts, Instruction startOfNextPart) { var inst0 = insts.First(); var instN = insts.Last(); // Any instruction in the method could target this block var blockStarts = this.methodBlockStarts .Where(x => x.Offset >= inst0.Offset && x.Offset <= instN.Offset) .ToArray(); // For each block create a StmtCil, with the correct ending. // Endings that require a expression have them set to null; they will be filled in during CIL decoding for (int i = 0; i < blockStarts.Length; i++) { var start = blockStarts[i]; var end = i == blockStarts.Length - 1 ? insts.Last() : blockStarts[i + 1].Previous; var blockInsts = start.GetRange(end); Stmt blockEndStmt; var code = end.OpCode.Code; switch (end.OpCode.FlowControl) { case FlowControl.Cond_Branch: if (code == Code.Switch) { var cases = ((Instruction[])end.Operand).Select(x => new StmtContinuation(this.ctx, x, false)).ToArray(); foreach (var @case in cases) { this.mappable.Add(@case); } var @default = new StmtContinuation(this.ctx, end.Next, false); this.mappable.Add(@default); blockEndStmt = new StmtSwitch(this.ctx, new ExprVarInstResult(this.ctx, end, this.ctx.Int32), cases.Select((x, value) => new StmtSwitch.Case(value, x)).ToArray(), @default); } else { var ifTrue = new StmtContinuation(this.ctx, (Instruction)end.Operand, false); var ifFalse = new StmtContinuation(this.ctx, end.Next, false); this.mappable.Add(ifTrue); this.mappable.Add(ifFalse); blockEndStmt = new StmtIf(this.ctx, new ExprVarInstResult(this.ctx, end, this.ctx.Boolean), ifTrue, ifFalse); } break; case FlowControl.Branch: var leaveProtectedRegion = code == Code.Leave || code == Code.Leave_S; blockEndStmt = new StmtContinuation(this.ctx, (Instruction)end.Operand, leaveProtectedRegion); this.mappable.Add((StmtContinuation)blockEndStmt); break; case FlowControl.Next: case FlowControl.Call: blockEndStmt = new StmtContinuation(this.ctx, end.Next, false); this.mappable.Add((StmtContinuation)blockEndStmt); break; case FlowControl.Return: switch (code) { case Code.Endfinally: blockEndStmt = new StmtContinuation(this.ctx, startOfNextPart, true); this.mappable.Add((StmtContinuation)blockEndStmt); break; case Code.Ret: blockEndStmt = new StmtContinuation(this.ctx, this.endBlock, false); blockInsts = start == end?Enumerable.Empty <Instruction>() : start.GetRange(end.Previous); // Remove 'ret' from statements break; default: blockEndStmt = null; break; } break; case FlowControl.Throw: blockEndStmt = null; break; default: throw new NotImplementedException("Cannot handle: " + end.OpCode.FlowControl); } var block = new StmtCil(this.ctx, blockInsts, blockEndStmt); this.blockMap.Add(start, new List <Stmt> { block }); } }
protected override ICode VisitCil(StmtCil s) { this.NewLine(); this.code.Append("CIL: " + s.ToString()); this.Visit(s.EndCil); return s; }
private void BuildBlock(IEnumerable<Instruction> insts, Instruction startOfNextPart) { var inst0 = insts.First(); var instN = insts.Last(); // Any instruction in the method could target this block var blockStarts = this.methodBlockStarts .Where(x => x.Offset >= inst0.Offset && x.Offset <= instN.Offset) .ToArray(); // For each block create a StmtCil, with the correct ending. // Endings that require a expression have them set to null; they will be filled in during CIL decoding for (int i = 0; i < blockStarts.Length; i++) { var start = blockStarts[i]; var end = i == blockStarts.Length - 1 ? insts.Last() : blockStarts[i + 1].Previous; var blockInsts = start.GetRange(end); Stmt blockEndStmt; var code = end.OpCode.Code; switch (end.OpCode.FlowControl) { case FlowControl.Cond_Branch: if (code == Code.Switch) { var cases = ((Instruction[])end.Operand).Select(x => new StmtContinuation(this.ctx, x, false)).ToArray(); foreach (var @case in cases) { this.mappable.Add(@case); } var @default = new StmtContinuation(this.ctx, end.Next, false); this.mappable.Add(@default); blockEndStmt = new StmtSwitch(this.ctx, new ExprVarInstResult(this.ctx, end, this.ctx.Int32), cases.Select((x, value) => new StmtSwitch.Case(value, x)).ToArray(), @default); } else { var ifTrue = new StmtContinuation(this.ctx, (Instruction)end.Operand, false); var ifFalse = new StmtContinuation(this.ctx, end.Next, false); this.mappable.Add(ifTrue); this.mappable.Add(ifFalse); blockEndStmt = new StmtIf(this.ctx, new ExprVarInstResult(this.ctx, end, this.ctx.Boolean), ifTrue, ifFalse); } break; case FlowControl.Branch: var leaveProtectedRegion = code == Code.Leave || code == Code.Leave_S; blockEndStmt = new StmtContinuation(this.ctx, (Instruction)end.Operand, leaveProtectedRegion); this.mappable.Add((StmtContinuation)blockEndStmt); break; case FlowControl.Next: case FlowControl.Call: blockEndStmt = new StmtContinuation(this.ctx, end.Next, false); this.mappable.Add((StmtContinuation)blockEndStmt); break; case FlowControl.Return: switch (code) { case Code.Endfinally: blockEndStmt = new StmtContinuation(this.ctx, startOfNextPart, true); this.mappable.Add((StmtContinuation)blockEndStmt); break; case Code.Ret: blockEndStmt = new StmtContinuation(this.ctx, this.endBlock, false); blockInsts = start == end ? Enumerable.Empty<Instruction>() : start.GetRange(end.Previous); // Remove 'ret' from statements break; default: blockEndStmt = null; break; } break; case FlowControl.Throw: blockEndStmt = null; break; default: throw new NotImplementedException("Cannot handle: " + end.OpCode.FlowControl); } var block = new StmtCil(this.ctx, blockInsts, blockEndStmt); this.blockMap.Add(start, new List<Stmt> { block }); } }
public Stmt Create() { var mDef = this.ctx.MRef.Resolve(); if (!mDef.HasBody) { throw new ArgumentException("Method has no body, cannot create AST"); } var body = mDef.Body; // Pre-calculate all method block starts this.methodBlockStarts = body.Instructions .SelectMany(x => { switch (x.OpCode.FlowControl) { case FlowControl.Cond_Branch: case FlowControl.Branch: if (x.OpCode.Code == Code.Switch) { return ((Instruction[])x.Operand).Concat(x.Next); } else { return new[] { (Instruction)x.Operand, x.Next }; } case FlowControl.Throw: case FlowControl.Return: return new[] { x.Next }; default: return Enumerable.Empty<Instruction>(); } }) .Concat(body.ExceptionHandlers.SelectMany(x => new[] { x.TryStart, x.TryEnd, x.HandlerStart, x.HandlerEnd })) .Concat(body.Instructions.First()) .Where(x => x != null) .Distinct() .OrderBy(x => x.Offset) .ToArray(); // Create all method blocks this.CreatePart(body.Instructions, body.ExceptionHandlers); // Map continuations and try statements // Must continue to outermost Try statement, if one exists, rather than directly to the first CIL block foreach (var mappable in this.mappable) { mappable.Map(this.blockMap); } var stmt0 = this.blockMap[body.Instructions.First()].First(); var vStackSize = new StackSizeVisitor(); vStackSize.Visit(stmt0); // Create entry block, and return it var entryBlock = new StmtCil(this.ctx, null, new StmtContinuation(this.ctx, stmt0, false), StmtCil.SpecialBlock.Start); return entryBlock; }