private void CreateOrMergeBsi(Stmt s, Expr[] stack, Expr[] locals, Expr[] args) {
     if (s.StmtType == Stmt.NodeType.Try) {
         var sTry = (StmtTry)s;
         // It is fine to use 'locals' and 'args' in catch/finally because the phi clustering performed later
         // will conglomerate all the necessary variables
         if (sTry.Catches != null) {
             var catch0 = sTry.Catches.First();
             this.CreateOrMergeBsi(catch0.Stmt, new Expr[] { catch0.ExceptionVar }, locals, args);
         }
         if (sTry.Finally != null) {
             this.CreateOrMergeBsi(sTry.Finally, new Expr[0], locals, args);
         }
         this.CreateOrMergeBsi(sTry.Try, stack, locals, args);
         return;
     }
     if (s.StmtType != Stmt.NodeType.Cil) {
         throw new InvalidCastException("Should not be seeing: " + s.StmtType);
     }
     // Perform create/merge
     Func<Expr, IEnumerable<Expr>> flattenPhiExprs = null;
     flattenPhiExprs = e => {
         if (e.ExprType == Expr.NodeType.VarPhi) {
             return ((ExprVarPhi)e).Exprs.SelectMany(x => flattenPhiExprs(x));
         }
         return new[] { e };
     };
     Action<ExprVarPhi[], IEnumerable<Expr>> merge = (bsiVars, thisVars) => {
         foreach (var v in bsiVars.Zip(thisVars, (a, b) => new { phi = a, add = b })) {
             if (v.add != null) {
                 v.phi.Exprs = flattenPhiExprs(v.add).Concat(v.phi.Exprs).Where(x => x != null && x != v.phi).Distinct().ToArray();
             }
         }
     };
     BlockInitInfo bsi;
     if (!this.blockStartInfos.TryGetValue(s, out bsi)) {
         Func<IEnumerable<Expr>, ExprVarPhi[]> create = exprs => exprs.Select(x => {
             if (x == null) {
                 return new ExprVarPhi(this.ctx) { Exprs = new Expr[0] };
             }
             if (x.ExprType == Expr.NodeType.VarPhi) {
                 return (ExprVarPhi)x;
             }
             return new ExprVarPhi(this.ctx) { Exprs = new[] { x } };
         }).ToArray();
         bsi = new BlockInitInfo {
             Stack = create(stack),
             Locals = create(locals),
             Args = create(args),
         };
         this.blockStartInfos.Add(s, bsi);
     } else {
         merge(bsi.Stack, stack);
         merge(bsi.Locals, locals);
         merge(bsi.Args, args);
         // Forward-merge through already-processed nodes for vars that are not changed in a node
         var fmSeen = new HashSet<Stmt>();
         Action<Stmt> forwardMerge = null;
         forwardMerge = (stmt) => {
             if (fmSeen.Add(stmt)) {
                 var fmBsi = this.blockStartInfos.ValueOrDefault(stmt);
                 var fmChanges = this.stmtVarsChanged.ValueOrDefault(stmt);
                 if (fmBsi != null && fmChanges != null) {
                     var fmStack = fmBsi.Stack.Take(fmChanges.Stack.Length).Select((x, i) => fmChanges.Stack[i] ? x : null).ToArray();
                     var fmLocals = fmBsi.Locals.Take(fmChanges.Locals.Length).Select((x, i) => fmChanges.Locals[i] ? x : null).ToArray();
                     var fmArgs = fmBsi.Args.Take(fmChanges.Args.Length).Select((x, i) => fmChanges.Args[i] ? x : null).ToArray();
                     if (fmStack.Any(x => x != null) || fmLocals.Any(x => x != null) || fmArgs.Any(x => x != null)) {
                         var fmConts = VisitorFindContinuations.Get(stmt);
                         foreach (var fmCont in fmConts) {
                             var fmContBsi = this.blockStartInfos.ValueOrDefault(fmCont.To);
                             if (fmContBsi != null) {
                                 merge(fmContBsi.Stack, fmStack);
                                 merge(fmContBsi.Locals, fmLocals);
                                 merge(fmContBsi.Args, fmArgs);
                                 forwardMerge(fmCont.To);
                             }
                         }
                     }
                 }
             }
         };
         forwardMerge(s);
     }
 }
Ejemplo n.º 2
0
        private void CreateOrMergeBsi(Stmt s, Expr[] stack, Expr[] locals, Expr[] args)
        {
            if (s.StmtType == Stmt.NodeType.Try)
            {
                var sTry = (StmtTry)s;
                // It is fine to use 'locals' and 'args' in catch/finally because the phi clustering performed later
                // will conglomerate all the necessary variables
                if (sTry.Catches != null)
                {
                    var catch0 = sTry.Catches.First();
                    this.CreateOrMergeBsi(catch0.Stmt, new Expr[] { catch0.ExceptionVar }, locals, args);
                }
                if (sTry.Finally != null)
                {
                    this.CreateOrMergeBsi(sTry.Finally, new Expr[0], locals, args);
                }
                this.CreateOrMergeBsi(sTry.Try, stack, locals, args);
                return;
            }
            if (s.StmtType != Stmt.NodeType.Cil)
            {
                throw new InvalidCastException("Should not be seeing: " + s.StmtType);
            }
            // Perform create/merge
            Func <Expr, IEnumerable <Expr> > flattenPhiExprs = null;

            flattenPhiExprs = e => {
                if (e.ExprType == Expr.NodeType.VarPhi)
                {
                    return(((ExprVarPhi)e).Exprs.SelectMany(x => flattenPhiExprs(x)));
                }
                return(new[] { e });
            };
            Action <ExprVarPhi[], IEnumerable <Expr> > merge = (bsiVars, thisVars) => {
                foreach (var v in bsiVars.Zip(thisVars, (a, b) => new { phi = a, add = b }))
                {
                    if (v.add != null)
                    {
                        v.phi.Exprs = flattenPhiExprs(v.add).Concat(v.phi.Exprs).Where(x => x != null && x != v.phi).Distinct().ToArray();
                    }
                }
            };
            BlockInitInfo bsi;

            if (!this.blockStartInfos.TryGetValue(s, out bsi))
            {
                Func <IEnumerable <Expr>, ExprVarPhi[]> create = exprs => exprs.Select(x => {
                    if (x == null)
                    {
                        return(new ExprVarPhi(this.ctx)
                        {
                            Exprs = new Expr[0]
                        });
                    }
                    if (x.ExprType == Expr.NodeType.VarPhi)
                    {
                        return((ExprVarPhi)x);
                    }
                    return(new ExprVarPhi(this.ctx)
                    {
                        Exprs = new[] { x }
                    });
                }).ToArray();
                bsi = new BlockInitInfo {
                    Stack  = create(stack),
                    Locals = create(locals),
                    Args   = create(args),
                };
                this.blockStartInfos.Add(s, bsi);
            }
            else
            {
                merge(bsi.Stack, stack);
                merge(bsi.Locals, locals);
                merge(bsi.Args, args);
                // Forward-merge through already-processed nodes for vars that are not changed in a node
                var           fmSeen       = new HashSet <Stmt>();
                Action <Stmt> forwardMerge = null;
                forwardMerge = (stmt) => {
                    if (fmSeen.Add(stmt))
                    {
                        var fmBsi     = this.blockStartInfos.ValueOrDefault(stmt);
                        var fmChanges = this.stmtVarsChanged.ValueOrDefault(stmt);
                        if (fmBsi != null && fmChanges != null)
                        {
                            var fmStack  = fmBsi.Stack.Take(fmChanges.Stack.Length).Select((x, i) => fmChanges.Stack[i] ? x : null).ToArray();
                            var fmLocals = fmBsi.Locals.Take(fmChanges.Locals.Length).Select((x, i) => fmChanges.Locals[i] ? x : null).ToArray();
                            var fmArgs   = fmBsi.Args.Take(fmChanges.Args.Length).Select((x, i) => fmChanges.Args[i] ? x : null).ToArray();
                            if (fmStack.Any(x => x != null) || fmLocals.Any(x => x != null) || fmArgs.Any(x => x != null))
                            {
                                var fmConts = VisitorFindContinuations.Get(stmt);
                                foreach (var fmCont in fmConts)
                                {
                                    var fmContBsi = this.blockStartInfos.ValueOrDefault(fmCont.To);
                                    if (fmContBsi != null)
                                    {
                                        merge(fmContBsi.Stack, fmStack);
                                        merge(fmContBsi.Locals, fmLocals);
                                        merge(fmContBsi.Args, fmArgs);
                                        forwardMerge(fmCont.To);
                                    }
                                }
                            }
                        }
                    }
                };
                forwardMerge(s);
            }
        }