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);
 }
Esempio n. 2
0
 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;
 }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
 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;
 }
Esempio n. 5
0
        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));
        }
Esempio n. 6
0
        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);
            }
        }
Esempio n. 7
0
            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);
 }
Esempio n. 9
0
        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
                });
            }
        }
Esempio n. 10
0
 protected override ICode VisitCil(StmtCil s) {
     this.NewLine();
     this.code.Append("CIL: " + s.ToString());
     this.Visit(s.EndCil);
     return s;
 }
Esempio n. 11
0
 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 });
     }
 }
Esempio n. 12
0
 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;
 }