Inheritance: Stmt, IInstructionMappable
 protected override ICode VisitContinuation(StmtContinuation s) {
     this.continuations.Add(s);
     if (this.seen.Add(s.To)) {
         this.todo.Enqueue(s.To);
     }
     return s;
 }
示例#2
0
 protected override ICode VisitContinuation(StmtContinuation s)
 {
     if (s.To == this.countReferences)
     {
         this.Count++;
     }
     return(base.VisitContinuation(s));
 }
示例#3
0
 protected override ICode VisitContinuation(StmtContinuation s)
 {
     this.continuations.Add(s);
     if (this.seen.Add(s.To))
     {
         this.todo.Enqueue(s.To);
     }
     return(s);
 }
 protected override ICode VisitContinuation(StmtContinuation s) {
     // TODO: Why is this de-recursing blocks in continuations? Why doesn't it just derecurse itself (if possible)???
     if (s.To.StmtType != Stmt.NodeType.Block) {
         return base.VisitContinuation(s);
     }
     if (!this.seen.Add(s.To)) {
         return base.VisitContinuation(s);
     }
     var block = (StmtBlock)s.To;
     foreach (var stmt in block.Statements) {
         if (stmt.StmtType == Stmt.NodeType.Continuation) {
             // Continuation not inside 'if'
             var sCont = (StmtContinuation)stmt;
             if (sCont.To == block) {
                 // Recursive, so derecurse with no condition on loop
                 var body = new StmtBlock(s.Ctx, block.Statements.TakeWhile(x => x != stmt).ToArray());
                 var replaceWith = new StmtDoLoop(s.Ctx, body, new ExprLiteral(s.Ctx, true, s.Ctx.Boolean));
                 this.replaces.Add(s.To, replaceWith);
                 return base.VisitContinuation(s);
             }
         }
         if (stmt.StmtType == Stmt.NodeType.If) {
             // Continuation only statement within 'if' with only a 'then' clause
             var sIf = (StmtIf)stmt;
             if (sIf.Else == null && sIf.Then.StmtType == Stmt.NodeType.Continuation) {
                 var sThen = (StmtContinuation)sIf.Then;
                 if (sThen.To == block) {
                     // Recursive, so derecurse
                     var condition = sIf.Condition;
                     var bodyStmts = block.Statements.TakeWhile(x => x != stmt).ToArray();
                     var bodyLast = bodyStmts.LastOrDefault();
                     var body = new StmtBlock(s.Ctx, bodyStmts);
                     var loop = new StmtDoLoop(s.Ctx, body, condition);
                     var afterLoop = block.Statements.SkipWhile(x => x != stmt).Skip(1).ToArray();
                     if (VisitorFindContinuations.Get(new StmtBlock(s.Ctx, afterLoop)).Any(x => x.To == block)) {
                         // Cannot de-recurse yet, must wait for continuations to be merged
                         return base.VisitContinuation(s);
                     }
                     Stmt replaceWith;
                     if (afterLoop.Any()) {
                         var loopAndAfter = new[] { loop }.Concat(afterLoop).ToArray();
                         replaceWith = new StmtBlock(s.Ctx, loopAndAfter);
                     } else {
                         replaceWith = loop;
                     }
                     this.replaces.Add(s.To, replaceWith);
                     return base.VisitContinuation(s);
                 }
             }
         }
         if (VisitorFindContinuations.Any(stmt)) {
             // Another continuation present, cannot derecurse
             break;
         }
     }
     return base.VisitContinuation(s);
 }
 protected override ICode VisitTry(StmtTry s) {
     var @try = this.RemoveContinuation(s.Try);
     if (@try != null) {
         if (s.Catches != null) {
             if (s.Catches.Count() != 1) {
                 throw new InvalidOperationException("Should only ever see 1 catch here");
             }
             var sCatch = s.Catches.First();
             var @catch = this.RemoveContinuation(sCatch.Stmt);
             if (@catch != null) {
                 if ((@try.Item2 == null || @catch.Item2 == null || @try.Item2 == @catch.Item2) && (@try.Item2 != null || @catch.Item2 != null)) {
                     var newTry = new StmtTry(s.Ctx, @try.Item1, new[] { new StmtTry.Catch(@catch.Item1, sCatch.ExceptionVar) }, null);
                     var newCont = new StmtContinuation(s.Ctx, @try.Item2 ?? @catch.Item2, false);
                     return new StmtBlock(s.Ctx, newTry, newCont);
                 }
             }
             // Special case
             // When 'leave' CIL branch to different instructions, allow specific code to be
             // moved inside the 'try' or 'catch' block. It should be impossible for this code to throw an exception
             var tryTos = VisitorFindContinuations.Get(@try.Item2);
             if (tryTos.Count() == 1 && tryTos.First().To == @catch.Item2 && @try.Item2.StmtType == Stmt.NodeType.Block) {
                 var try2Stmts = ((StmtBlock)@try.Item2).Statements.ToArray();
                 var s0 = try2Stmts.Take(try2Stmts.Length - 1);
                 if (s0.All(x => x.StmtType == Stmt.NodeType.Assignment)) {
                     var sN = try2Stmts.Last();
                     if (sN.StmtType == Stmt.NodeType.Continuation) {
                         var newTry = new StmtTry(s.Ctx,
                             new StmtBlock(s.Ctx, @try.Item1, new StmtBlock(s.Ctx, s0), new StmtContinuation(s.Ctx, ((StmtContinuation)sN).To, true)),
                             s.Catches, null);
                         return newTry;
                     }
                 }
             }
         }
         if (s.Finally != null) {
             var @finally = this.RemoveContinuation(s.Finally);
             if (@finally != null) {
                 if ((@try.Item2 == null || @finally.Item2 == null || @try.Item2 == @finally.Item2) && (@try.Item2 != null || @finally.Item2 != null)) {
                     var newTry = new StmtTry(s.Ctx, @try.Item1, null, @finally.Item1);
                     var newCont = new StmtContinuation(s.Ctx, @try.Item2 ?? @finally.Item2, false);
                     return new StmtBlock(s.Ctx, newTry, newCont);
                 }
             }
         }
         // TODO: This is a hack for badly handling fault handlers. They are ignored at the moment
         if (s.Catches == null && s.Finally == null) {
             var cont = @try.Item2 == null ? null : new StmtContinuation(s.Ctx, @try.Item2, false);
             return new StmtBlock(s.Ctx, @try.Item1, cont);
         }
     }
     return base.VisitTry(s);
 }
 protected override ICode VisitContinuation(StmtContinuation s) {
     if (this.ifInfo == null) {
         // If there are no if statements in this continuation
         return base.VisitContinuation(s);
     }
     if (!this.ifInfo.Conditions.Any()) {
         throw new InvalidOperationException("There should be one or more conditions at this point");
     }
     var combinedCondition = this.ifInfo.Conditions.Aggregate((a, b) => this.ctx.ExprGen.And(a, b));
     this.ifInfo.AddToIf.Add(Tuple.Create(s, combinedCondition));
     base.VisitContinuation(s);
     return null;
 }
 protected override ICode VisitContinuation(StmtContinuation s) {
     if (!s.LeaveProtectedRegion) {
         // Must never substitute when leaving protected region.
         // This would change which statements were inside the try/catch/finally region
         if (s.To.StmtType == Stmt.NodeType.Continuation && !((StmtContinuation)s.To).LeaveProtectedRegion) {
             var newCont = new StmtContinuation(s.Ctx, ((StmtContinuation)s.To).To, false);
             return this.Visit(newCont);
         }
         var count = VisitorContToCounter.GetCount(s.To, this.root);
         if (count == 1) {
             return this.Visit(s.To);
         }
     }
     return base.VisitContinuation(s);
 }
        protected override ICode VisitContinuation(StmtContinuation s)
        {
            if (this.ifInfo == null)
            {
                // If there are no if statements in this continuation
                return(base.VisitContinuation(s));
            }
            if (!this.ifInfo.Conditions.Any())
            {
                throw new InvalidOperationException("There should be one or more conditions at this point");
            }
            var combinedCondition = this.ifInfo.Conditions.Aggregate((a, b) => this.ctx.ExprGen.And(a, b));

            this.ifInfo.AddToIf.Add(Tuple.Create(s, combinedCondition));
            base.VisitContinuation(s);
            return(null);
        }
 protected override ICode VisitContinuation(StmtContinuation s)
 {
     if (!s.LeaveProtectedRegion)
     {
         // Must never substitute when leaving protected region.
         // This would change which statements were inside the try/catch/finally region
         if (s.To.StmtType == Stmt.NodeType.Continuation && !((StmtContinuation)s.To).LeaveProtectedRegion)
         {
             var newCont = new StmtContinuation(s.Ctx, ((StmtContinuation)s.To).To, false);
             return(this.Visit(newCont));
         }
         var count = VisitorContToCounter.GetCount(s.To, this.root);
         if (count == 1)
         {
             return(this.Visit(s.To));
         }
     }
     return(base.VisitContinuation(s));
 }
 protected override ICode VisitContinuation(StmtContinuation s) {
     return new StmtContinuation(s.Ctx, s.To, s.LeaveProtectedRegion);
 }
示例#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
                });
            }
        }
 protected override ICode VisitContinuation(StmtContinuation s) {
     this.continuations.Add(s);
     return s;
 }
示例#13
0
 protected override ICode VisitContinuation(StmtContinuation s)
 {
     return(new StmtContinuation(s.Ctx, s.To, s.LeaveProtectedRegion));
 }
        protected override ICode VisitTry(StmtTry s)
        {
            var @try = this.RemoveContinuation(s.Try);

            if (@try != null)
            {
                if (s.Catches != null)
                {
                    if (s.Catches.Count() != 1)
                    {
                        throw new InvalidOperationException("Should only ever see 1 catch here");
                    }
                    var sCatch = s.Catches.First();
                    var @catch = this.RemoveContinuation(sCatch.Stmt);
                    if (@catch != null)
                    {
                        if ((@try.Item2 == null || @catch.Item2 == null || @try.Item2 == @catch.Item2) && (@try.Item2 != null || @catch.Item2 != null))
                        {
                            var newTry  = new StmtTry(s.Ctx, @try.Item1, new[] { new StmtTry.Catch(@catch.Item1, sCatch.ExceptionVar) }, null);
                            var newCont = new StmtContinuation(s.Ctx, @try.Item2 ?? @catch.Item2, false);
                            return(new StmtBlock(s.Ctx, newTry, newCont));
                        }
                    }
                    // Special case
                    // When 'leave' CIL branch to different instructions, allow specific code to be
                    // moved inside the 'try' or 'catch' block. It should be impossible for this code to throw an exception
                    var tryTos = VisitorFindContinuations.Get(@try.Item2);
                    if (tryTos.Count() == 1 && tryTos.First().To == @catch.Item2 && @try.Item2.StmtType == Stmt.NodeType.Block)
                    {
                        var try2Stmts = ((StmtBlock)@try.Item2).Statements.ToArray();
                        var s0        = try2Stmts.Take(try2Stmts.Length - 1);
                        if (s0.All(x => x.StmtType == Stmt.NodeType.Assignment))
                        {
                            var sN = try2Stmts.Last();
                            if (sN.StmtType == Stmt.NodeType.Continuation)
                            {
                                var newTry = new StmtTry(s.Ctx,
                                                         new StmtBlock(s.Ctx, @try.Item1, new StmtBlock(s.Ctx, s0), new StmtContinuation(s.Ctx, ((StmtContinuation)sN).To, true)),
                                                         s.Catches, null);
                                return(newTry);
                            }
                        }
                    }
                }
                if (s.Finally != null)
                {
                    var @finally = this.RemoveContinuation(s.Finally);
                    if (@finally != null)
                    {
                        if ((@try.Item2 == null || @finally.Item2 == null || @try.Item2 == @finally.Item2) && (@try.Item2 != null || @finally.Item2 != null))
                        {
                            var newTry  = new StmtTry(s.Ctx, @try.Item1, null, @finally.Item1);
                            var newCont = new StmtContinuation(s.Ctx, @try.Item2 ?? @finally.Item2, false);
                            return(new StmtBlock(s.Ctx, newTry, newCont));
                        }
                    }
                }
                // TODO: This is a hack for badly handling fault handlers. They are ignored at the moment
                if (s.Catches == null && s.Finally == null)
                {
                    var cont = @try.Item2 == null ? null : new StmtContinuation(s.Ctx, @try.Item2, false);
                    return(new StmtBlock(s.Ctx, @try.Item1, cont));
                }
            }
            return(base.VisitTry(s));
        }
示例#15
0
 protected virtual ICode VisitContinuation(StmtContinuation s)
 {
     throw new InvalidOperationException("Non-recursive visitor, cannot handle continuations");
 }
示例#16
0
 protected override ICode VisitContinuation(StmtContinuation s)
 {
     // Don't continue through continuations
     return(s);
 }
示例#17
0
 protected override ICode VisitContinuation(StmtContinuation s)
 {
     this.numConts++;
     this.containsLeaveProtectedRegion |= s.LeaveProtectedRegion;
     return(base.VisitContinuation(s));
 }
示例#18
0
        protected override ICode VisitContinuation(StmtContinuation s)
        {
            // TODO: Why is this de-recursing blocks in continuations? Why doesn't it just derecurse itself (if possible)???
            if (s.To.StmtType != Stmt.NodeType.Block)
            {
                return(base.VisitContinuation(s));
            }
            if (!this.seen.Add(s.To))
            {
                return(base.VisitContinuation(s));
            }
            var block = (StmtBlock)s.To;

            foreach (var stmt in block.Statements)
            {
                if (stmt.StmtType == Stmt.NodeType.Continuation)
                {
                    // Continuation not inside 'if'
                    var sCont = (StmtContinuation)stmt;
                    if (sCont.To == block)
                    {
                        // Recursive, so derecurse with no condition on loop
                        var body        = new StmtBlock(s.Ctx, block.Statements.TakeWhile(x => x != stmt).ToArray());
                        var replaceWith = new StmtDoLoop(s.Ctx, body, new ExprLiteral(s.Ctx, true, s.Ctx.Boolean));
                        this.replaces.Add(s.To, replaceWith);
                        return(base.VisitContinuation(s));
                    }
                }
                if (stmt.StmtType == Stmt.NodeType.If)
                {
                    // Continuation only statement within 'if' with only a 'then' clause
                    var sIf = (StmtIf)stmt;
                    if (sIf.Else == null && sIf.Then.StmtType == Stmt.NodeType.Continuation)
                    {
                        var sThen = (StmtContinuation)sIf.Then;
                        if (sThen.To == block)
                        {
                            // Recursive, so derecurse
                            var condition = sIf.Condition;
                            var bodyStmts = block.Statements.TakeWhile(x => x != stmt).ToArray();
                            var bodyLast  = bodyStmts.LastOrDefault();
                            var body      = new StmtBlock(s.Ctx, bodyStmts);
                            var loop      = new StmtDoLoop(s.Ctx, body, condition);
                            var afterLoop = block.Statements.SkipWhile(x => x != stmt).Skip(1).ToArray();
                            if (VisitorFindContinuations.Get(new StmtBlock(s.Ctx, afterLoop)).Any(x => x.To == block))
                            {
                                // Cannot de-recurse yet, must wait for continuations to be merged
                                return(base.VisitContinuation(s));
                            }
                            Stmt replaceWith;
                            if (afterLoop.Any())
                            {
                                var loopAndAfter = new[] { loop }.Concat(afterLoop).ToArray();
                                replaceWith = new StmtBlock(s.Ctx, loopAndAfter);
                            }
                            else
                            {
                                replaceWith = loop;
                            }
                            this.replaces.Add(s.To, replaceWith);
                            return(base.VisitContinuation(s));
                        }
                    }
                }
                if (VisitorFindContinuations.Any(stmt))
                {
                    // Another continuation present, cannot derecurse
                    break;
                }
            }
            return(base.VisitContinuation(s));
        }
 protected override ICode VisitContinuation(StmtContinuation s) {
     this.numConts++;
     this.containsLeaveProtectedRegion |= s.LeaveProtectedRegion;
     return base.VisitContinuation(s);
 }
 protected override ICode VisitContinuation(StmtContinuation s) {
     // Don't continue through continuations
     return s;
 }
示例#21
0
 protected override ICode VisitContinuation(StmtContinuation s)
 {
     this.continuations.Add(s);
     return(s);
 }
示例#22
0
 public DebugView(StmtContinuation s)
 {
     this.to = s.to;
     this.To = s.To;
 }
 protected override ICode VisitContinuation(StmtContinuation s) {
     if (s.To == this.countReferences) {
         this.Count++;
     }
     return base.VisitContinuation(s);
 }
示例#24
0
 protected override ICode VisitContinuation(StmtContinuation s) {
     this.NewLine();
     this.code.AppendFormat("-> {0}", GetStmtName(s.To));
     if (s.LeaveProtectedRegion) {
         this.code.Append(" [leave protected region]");
     }
     this.continuations.Add(s);
     return s;
 }
 public DebugView(StmtContinuation s) {
     this.to = s.to;
     this.To = s.To;
 }
 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 });
     }
 }