コード例 #1
0
 public virtual void Write(ILSwitch f)
 {
     InsertLineInfo(f);
     Write("switch(");
     Write(f.Condition);
     WriteLine(") {");
     Indent++;
     foreach (var c in f.Cases)
     {
         if (c.Values == null)
         {
             WriteLine("default:");
         }
         else
         {
             foreach (var v in c.Values)
             {
                 Write("case ");
                 Write(v);
                 WriteLine(":");
             }
         }
         Write((ILBlock)c);  // write it as a block
     }
     if (f.Default != null && f.Default.Body.Count > 0)
     {
         Write("default:");
         Write(f.Default);
     }
     Indent--;
     Write("}");
 }
コード例 #2
0
ファイル: ILNodeVisitor.cs プロジェクト: ropean/Usable
 protected virtual ILSwitch VisitSwitch(ILSwitch switchStatement)
 {
     foreach (var child in switchStatement.GetChildren())
     {
         Visit(child);
     }
     return(switchStatement);
 }
コード例 #3
0
        private void CompileSwitch(ILSwitch node)
        {
            CompileExpression(node.Condition, ExpectType.Primitive);  //TODO: Switch on long

            JavaBytecodeWriter.LookupswitchOperand operand = new JavaBytecodeWriter.LookupswitchOperand();

            JavaInstruction switchInstr = new JavaInstruction(Java.OpCodes.lookupswitch, null, node);

            codeGenerator.AddInstruction(switchInstr);

            string labelsSufix  = rnd.Next().ToString();
            string defaultLabel = "default" + labelsSufix;
            string exitLabel    = "exit" + labelsSufix;
            bool   wasDefault   = false;
            List <Tuple <int, string> > pairs = new List <Tuple <int, string> >();

            loopOrSwitchExitLabel.Push(exitLabel);
            int index = 0;

            foreach (ILSwitch.CaseBlock caseBlock in node.CaseBlocks)
            {
                if (caseBlock.Values == null)
                {
                    codeGenerator.Label(defaultLabel);
                    wasDefault = true;
                }
                else
                {
                    string thisCaseLabel = "case" + (index++) + labelsSufix;
                    foreach (int val in caseBlock.Values)
                    {
                        pairs.Add(new Tuple <int, string>(val, thisCaseLabel));
                    }
                    codeGenerator.Label(thisCaseLabel);
                }

                CompileBlock(caseBlock);
            }
            loopOrSwitchExitLabel.Pop();

            if (!wasDefault)
            {
                codeGenerator.Label(defaultLabel);
            }
            codeGenerator.Label(exitLabel);

            pairs.Sort((T1, T2) => (T1.Item1 <T2.Item1 ? -1 : T1.Item1> T2.Item1 ? 1 : 0));

            operand.DefaultLabel = defaultLabel;
            operand.Pairs        = pairs.ToArray();
            switchInstr.Operand  = operand;
        }
コード例 #4
0
        public JSSwitchCase TranslateNode(ILSwitch.CaseBlock block, TypeReference conditionType = null)
        {
            JSExpression[] values = null;

            if (block.Values != null) {
                if ((conditionType != null) && (conditionType.MetadataType == MetadataType.Char)) {
                    values = (from v in block.Values select JSLiteral.New(Convert.ToChar(v))).ToArray();
                } else {
                    values = (from v in block.Values select JSLiteral.New(v)).ToArray();
                }
            }

            return new JSSwitchCase(
                values,
                TranslateNode(new ILBlock(block.Body))
            );
        }
コード例 #5
0
ファイル: ILAstOptimizer.cs プロジェクト: petr-k/ILSpy
        List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode)
        {
            List<ILNode> result = new List<ILNode>();

            HashSet<ControlFlowNode> agenda  = new HashSet<ControlFlowNode>();
            agenda.Add(entryNode);
            while(agenda.Any()) {
                ControlFlowNode node = agenda.First();
                // Attempt for a good order
                while(agenda.Contains(node.ImmediateDominator)) {
                    node = node.ImmediateDominator;
                }
                agenda.Remove(node);

                // Find a block that represents a simple condition
                if (scope.Contains(node)) {

                    ILBasicBlock block = node.UserData as ILBasicBlock;

                    if (block != null && block.Body.Count == 1) {

                        ILExpression condBranch = block.Body[0] as ILExpression;

                        // Switch
                        if (condBranch != null && condBranch.Operand is ILLabel[] && condBranch.Arguments.Count > 0) {

                            ILSwitch ilSwitch = new ILSwitch() {
                                Condition = condBranch,
                                DefaultGoto = block.FallthoughGoto
                            };

                            ControlFlowNode fallTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)block.FallthoughGoto.Operand, out fallTarget);

                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
                            if (fallTarget != null)
                                frontiers.UnionWith(fallTarget.DominanceFrontier);

                            foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);
                                if (condTarget != null)
                                    frontiers.UnionWith(condTarget.DominanceFrontier);
                            }

                            foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);

                                ILBlock caseBlock = new ILBlock() {
                                    EntryGoto = new ILExpression(ILCode.Br, condLabel)
                                };
                                if (condTarget != null && !frontiers.Contains(condTarget)) {
                                    HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
                                    scope.ExceptWith(content);
                                    caseBlock.Body.AddRange(FindConditions(content, condTarget));
                                }
                                ilSwitch.CaseBlocks.Add(caseBlock);
                            }

                            // The labels will not be used - kill them
                            condBranch.Operand = null;

                            result.Add(new ILBasicBlock() {
                                EntryLabel = block.EntryLabel,  // Keep the entry label
                                Body = { ilSwitch }
                            });
                            scope.Remove(node);
                        }

                        // Two-way branch
                        ILCondition ilCond;
                        HashSet<ControlFlowNode> matchedNodes;
                        ILLabel condEntryLabel;
                        if (TryMatchCondition(scope, new ControlFlowNode[] {}, node, out ilCond, out matchedNodes, out condEntryLabel)) {

                            // The branch labels will not be used - kill them
                            foreach(ILExpression expr in ilCond.Condition.GetSelfAndChildrenRecursive<ILExpression>()) {
                                if (expr.GetBranchTargets().Any()) {
                                    expr.Operand = null;
                                }
                            }

                            ControlFlowNode trueTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)ilCond.TrueBlock.EntryGoto.Operand, out trueTarget);
                            ControlFlowNode falseTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)ilCond.FalseBlock.EntryGoto.Operand, out falseTarget);

                            // Pull in the conditional code
                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
                            if (trueTarget != null)
                                frontiers.UnionWith(trueTarget.DominanceFrontier);
                            if (falseTarget != null)
                                frontiers.UnionWith(falseTarget.DominanceFrontier);

                            if (trueTarget != null && !frontiers.Contains(trueTarget)) {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
                                scope.ExceptWith(content);
                                ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget));
                            }
                            if (falseTarget != null && !frontiers.Contains(falseTarget)) {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
                                scope.ExceptWith(content);
                                ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget));
                            }

                            result.Add(new ILBasicBlock() {
                                EntryLabel = condEntryLabel,  // Keep the entry label
                                Body = { ilCond }
                            });
                            scope.ExceptWith(matchedNodes);
                        }
                    }

                    // Add the node now so that we have good ordering
                    if (scope.Contains(node)) {
                        result.Add((ILNode)node.UserData);
                        scope.Remove(node);
                    }
                }

                // Using the dominator tree should ensure we find the the widest loop first
                foreach(var child in node.DominatorTreeChildren) {
                    agenda.Add(child);
                }
            }

            // Add whatever is left
            foreach(var node in scope) {
                result.Add((ILNode)node.UserData);
            }

            return result;
        }
コード例 #6
0
        private List <ILVariable> PreprocessorCheckUninitializedLocalVarsBranch(ILBlock branch, List <ILVariable> initializedVars)
        {
            List <ILVariable> result = new List <ILVariable>(initializedVars);

            foreach (ILNode node in branch.Body)
            {
                if (node is ILExpression)
                {
                    PreprocessorCheckUninitializedLocalVarsExpression((ILExpression)node, result);
                }
                else if (node is ILBlock)
                {
                    result = PreprocessorCheckUninitializedLocalVarsBranch((ILBlock)node, result);
                }
                else if (node is ILTryCatchBlock)
                {
                    ILTryCatchBlock block = (ILTryCatchBlock)node;

                    List <ILVariable> newResult = new List <ILVariable>(result);

                    if (block.TryBlock != null)
                    {
                        newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(block.TryBlock, result)).ToList();
                    }
                    if (block.FaultBlock != null)
                    {
                        newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(block.FaultBlock, result)).ToList();
                    }
                    if (block.FinallyBlock != null)
                    {
                        newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(block.FinallyBlock, result)).ToList();
                    }
                    if (block.CatchBlocks != null)
                    {
                        foreach (ILTryCatchBlock.CatchBlock c in block.CatchBlocks)
                        {
                            newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(c, result)).ToList();
                        }
                    }

                    result = newResult;
                }
                else if (node is ILWhileLoop)
                {
                    PreprocessorCheckUninitializedLocalVarsExpression(((ILWhileLoop)node).Condition, result);
                    result = PreprocessorCheckUninitializedLocalVarsBranch(((ILWhileLoop)node).BodyBlock, result);
                }
                else if (node is ILCondition)
                {
                    ILCondition cond = (ILCondition)node;
                    PreprocessorCheckUninitializedLocalVarsExpression(cond.Condition, result);

                    List <ILVariable> fromTrue  = PreprocessorCheckUninitializedLocalVarsBranch(cond.TrueBlock, result);
                    List <ILVariable> fromFalse = PreprocessorCheckUninitializedLocalVarsBranch(cond.FalseBlock, result);

                    result = fromTrue.Union(fromFalse).ToList();
                }
                else if (node is ILSwitch)
                {
                    ILSwitch sw = (ILSwitch)node;

                    PreprocessorCheckUninitializedLocalVarsExpression(sw.Condition, result);

                    List <ILVariable> newResult = new List <ILVariable>(result);
                    foreach (var cas in sw.CaseBlocks)
                    {
                        newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(cas, result)).ToList();
                    }
                    result = newResult;
                }
            }

            return(result);
        }
コード例 #7
0
        /// <summary>
        /// Get the first expression to be excecuted if the instruction pointer is at the start of the given node.
        /// Try blocks may not be entered in any way.  If possible, the try block is returned as the node to be executed.
        /// </summary>
        ILNode Enter(ILNode node, HashSet <ILNode> visitedNodes)
        {
            if (node == null)
            {
                throw new ArgumentNullException();
            }

            if (!visitedNodes.Add(node))
            {
                return(null);  // Infinite loop
            }
            ILLabel label = node as ILLabel;

            if (label != null)
            {
                return(Exit(label, visitedNodes));
            }


            ILExpression expr = node as ILExpression;

            if (expr != null)
            {
                if (expr.Code == GMCode.B)
                {
                    ILLabel target = (ILLabel)expr.Operand;
                    return(Enter(target, visitedNodes));
                }
                else if (expr.Code == GMCode.BadOp || expr.Code == GMCode.Constant || expr.Code == GMCode.Var)
                {
                    return(Exit(expr, visitedNodes));
                }
                else if (expr.Code == GMCode.LoopOrSwitchBreak)
                {
                    ILNode breakBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILSwitch || n is ILWithStatement);
                    return(Exit(breakBlock, new HashSet <ILNode>()
                    {
                        expr
                    }));
                }
                else if (expr.Code == GMCode.LoopContinue)
                {
                    ILNode continueBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILWithStatement);
                    return(Enter(continueBlock, new HashSet <ILNode>()
                    {
                        expr
                    }));
                }
                else
                {
                    return(expr);
                }
            }

            ILBlock block = node as ILBlock;

            if (block != null)
            {
                if (block.EntryGoto != null)
                {
                    return(Enter(block.EntryGoto, visitedNodes));
                }
                else if (block.Body.Count > 0)
                {
                    return(Enter(block.Body[0], visitedNodes));
                }
                else
                {
                    return(Exit(block, visitedNodes));
                }
            }

            ILCondition cond = node as ILCondition;

            if (cond != null)
            {
                return(cond.Condition);
            }

            ILWhileLoop loop = node as ILWhileLoop;

            if (loop != null)
            {
                if (loop.Condition != null)
                {
                    return(loop.Condition);
                }
                else
                {
                    return(Enter(loop.Body, visitedNodes));
                }
            }

            ILSwitch ilSwitch = node as ILSwitch;

            if (ilSwitch != null)
            {
                return(ilSwitch.Condition);
            }

            throw new NotSupportedException(node.GetType().ToString());
        }
コード例 #8
0
        /// <summary>
        /// Get the first expression to be excecuted if the instruction pointer is at the start of the given node.
        /// Try blocks may not be entered in any way.  If possible, the try block is returned as the node to be executed.
        /// </summary>
        ILNode Enter(ILNode node, HashSet <ILNode> visitedNodes)
        {
            if (node == null)
            {
                throw new ArgumentNullException();
            }

            if (!visitedNodes.Add(node))
            {
                return(null);                 // Infinite loop
            }
            ILLabel label = node as ILLabel;

            if (label != null)
            {
                return(Exit(label, visitedNodes));
            }

            ILExpression expr = node as ILExpression;

            if (expr != null)
            {
                if (expr.Code == ILCode.Br || expr.Code == ILCode.Leave)
                {
                    ILLabel target = (ILLabel)expr.Operand;
                    // Early exit - same try-block
                    if (GetParents(expr).OfType <ILTryCatchBlock>().FirstOrDefault() == GetParents(target).OfType <ILTryCatchBlock>().FirstOrDefault())
                    {
                        return(Enter(target, visitedNodes));
                    }
                    // Make sure we are not entering any try-block
                    var srcTryBlocks = GetParents(expr).OfType <ILTryCatchBlock>().Reverse().ToList();
                    var dstTryBlocks = GetParents(target).OfType <ILTryCatchBlock>().Reverse().ToList();
                    // Skip blocks that we are already in
                    int i = 0;
                    while (i < srcTryBlocks.Count && i < dstTryBlocks.Count && srcTryBlocks[i] == dstTryBlocks[i])
                    {
                        i++;
                    }
                    if (i == dstTryBlocks.Count)
                    {
                        return(Enter(target, visitedNodes));
                    }
                    else
                    {
                        ILTryCatchBlock dstTryBlock = dstTryBlocks[i];
                        // Check that the goto points to the start
                        ILTryCatchBlock current = dstTryBlock;
                        while (current != null)
                        {
                            foreach (ILNode n in current.TryBlock.Body)
                            {
                                if (n is ILLabel)
                                {
                                    if (n == target)
                                    {
                                        return(dstTryBlock);
                                    }
                                }
                                else if (!n.Match(ILCode.Nop))
                                {
                                    current = n as ILTryCatchBlock;
                                    break;
                                }
                            }
                        }
                        return(null);
                    }
                }
                else if (expr.Code == ILCode.Nop)
                {
                    return(Exit(expr, visitedNodes));
                }
                else if (expr.Code == ILCode.LoopOrSwitchBreak)
                {
                    ILNode breakBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILSwitch);
                    return(Exit(breakBlock, new HashSet <ILNode>()
                    {
                        expr
                    }));
                }
                else if (expr.Code == ILCode.LoopContinue)
                {
                    ILNode continueBlock = GetParents(expr).First(n => n is ILWhileLoop);
                    return(Enter(continueBlock, new HashSet <ILNode>()
                    {
                        expr
                    }));
                }
                else
                {
                    return(expr);
                }
            }

            ILBlock block = node as ILBlock;

            if (block != null)
            {
                if (block.EntryGoto != null)
                {
                    return(Enter(block.EntryGoto, visitedNodes));
                }
                else if (block.Body.Count > 0)
                {
                    return(Enter(block.Body[0], visitedNodes));
                }
                else
                {
                    return(Exit(block, visitedNodes));
                }
            }

            ILCondition cond = node as ILCondition;

            if (cond != null)
            {
                return(cond.Condition);
            }

            ILWhileLoop loop = node as ILWhileLoop;

            if (loop != null)
            {
                if (loop.Condition != null)
                {
                    return(loop.Condition);
                }
                else
                {
                    return(Enter(loop.BodyBlock, visitedNodes));
                }
            }

            ILTryCatchBlock tryCatch = node as ILTryCatchBlock;

            if (tryCatch != null)
            {
                return(tryCatch);
            }

            ILSwitch ilSwitch = node as ILSwitch;

            if (ilSwitch != null)
            {
                return(ilSwitch.Condition);
            }

            throw new NotSupportedException(node.GetType().ToString());
        }
コード例 #9
0
ファイル: ILNodeVisitor.cs プロジェクト: ropean/Usable
 protected virtual ILSwitch VisitSwitch(ILSwitch switchStatement)
 {
     foreach (var child in switchStatement.GetChildren())
         Visit(child);
     return switchStatement;
 }
コード例 #10
0
ファイル: ILAstOptimizer.cs プロジェクト: FriedWishes/ILSpy
        List<ILNode> FindConditions(HashSet<ControlFlowNode> nodes, ControlFlowNode entryNode)
        {
            List<ILNode> result = new List<ILNode>();

            Queue<ControlFlowNode> agenda  = new Queue<ControlFlowNode>();
            agenda.Enqueue(entryNode);
            while(agenda.Count > 0) {
                ControlFlowNode node = agenda.Dequeue();

                // Find a block that represents a simple condition
                if (nodes.Contains(node)) {

                    ILMoveableBlock block = node.UserData as ILMoveableBlock;

                    if (block != null && block.Body.Count == 3) {

                        ILLabel      label      = block.Body[0] as ILLabel;
                        ILExpression condBranch = block.Body[1] as ILExpression;
                        ILExpression statBranch = block.Body[2] as ILExpression;

                        // Switch
                        if (label != null &&
                            condBranch != null && condBranch.Operand is ILLabel[] && condBranch.Arguments.Count > 0 &&
                            statBranch != null && statBranch.Operand is ILLabel   && statBranch.Arguments.Count == 0)
                        {
                            ILSwitch ilSwitch = new ILSwitch() { Condition = condBranch };

                            // Replace the two branches with a conditional structure - this preserves the node label
                            block.Body.Remove(condBranch);
                            block.Body.Remove(statBranch);
                            block.Body.Add(ilSwitch);

                            ControlFlowNode statTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)statBranch.Operand, out statTarget);

                            // Pull in the conditional code
                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();

                            if (statTarget != null)
                                frontiers.UnionWith(statTarget.DominanceFrontier);

                            foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);

                                if (condTarget != null)
                                    frontiers.UnionWith(condTarget.DominanceFrontier);
                            }

                            foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);

                                ILBlock caseBlock = new ILBlock() { EntryPoint = condLabel };
                                if (condTarget != null && !frontiers.Contains(condTarget)) {
                                    HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, condTarget);
                                    nodes.ExceptWith(content);
                                    caseBlock.Body.AddRange(FindConditions(content, condTarget));
                                }
                                ilSwitch.CaseBlocks.Add(caseBlock);
                            }

                            // The labels will not be used - kill them
                            condBranch.Operand = null;

                            result.Add(block);
                            nodes.Remove(node);
                        }

                        // Two-way branch
                        if (label != null &&
                            condBranch != null && condBranch.Operand is ILLabel && condBranch.Arguments.Count > 0 &&
                            statBranch != null && statBranch.Operand is ILLabel && statBranch.Arguments.Count == 0)
                        {
                            ControlFlowNode statTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)statBranch.Operand, out statTarget);
                            ControlFlowNode condTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)condBranch.Operand, out condTarget);

                            ILCondition condition = new ILCondition() {
                                Condition  = condBranch,
                                TrueBlock  = new ILBlock() { EntryPoint = (ILLabel)condBranch.Operand },
                                FalseBlock = new ILBlock() { EntryPoint = (ILLabel)statBranch.Operand }
                            };

                            // Replace the two branches with a conditional structure - this preserves the node label
                            block.Body.Remove(condBranch);
                            block.Body.Remove(statBranch);
                            block.Body.Add(condition);

                            // Pull in the conditional code
                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
                            if (statTarget != null)
                                frontiers.UnionWith(statTarget.DominanceFrontier);
                            if (condTarget != null)
                                frontiers.UnionWith(condTarget.DominanceFrontier);

                            if (condTarget != null && !frontiers.Contains(condTarget)) {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, condTarget);
                                nodes.ExceptWith(content);
                                condition.TrueBlock.Body.AddRange(FindConditions(content, condTarget));
                            }
                            if (statTarget != null && !frontiers.Contains(statTarget)) {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, statTarget);
                                nodes.ExceptWith(content);
                                condition.FalseBlock.Body.AddRange(FindConditions(content, statTarget));
                            }

                            // The label will not be used - kill it
                            condBranch.Operand = null;

                            result.Add(block);
                            nodes.Remove(node);
                        }
                    }

                    // Add the node now so that we have good ordering
                    if (nodes.Contains(node)) {
                        result.Add((ILNode)node.UserData);
                        nodes.Remove(node);
                    }
                }

                // Using the dominator tree should ensure we find the the widest loop first
                foreach(var child in node.DominatorTreeChildren) {
                    agenda.Enqueue(child);
                }
            }

            // Add whatever is left
            foreach(var node in nodes) {
                result.Add((ILNode)node.UserData);
            }

            return result;
        }
コード例 #11
0
        List <ILNode> FindConditions(HashSet <ControlFlowNode> scope, ControlFlowNode entryNode)
        {
            List <ILNode> result = new List <ILNode>();

            // Do not modify entry data
            scope = new HashSet <ControlFlowNode>(scope);

            Stack <ControlFlowNode> agenda = new Stack <ControlFlowNode>();

            agenda.Push(entryNode);
            while (agenda.Count > 0)
            {
                ControlFlowNode node = agenda.Pop();

                // Find a block that represents a simple condition
                if (scope.Contains(node))
                {
                    ILBasicBlock block = (ILBasicBlock)node.UserData;

                    {
                        IList <ILExpression> conditions;
                        ILLabel fallLabel;
                        // Switch
                        FakeSwitch fswitch;
                        if (block.MatchLastAndBr(GMCode.Switch, out fswitch, out conditions, out fallLabel))
                        {
                            ILSwitch ilSwitch = new ILSwitch()
                            {
                                Condition = fswitch.SwitchExpression
                            };
                            block.Body[block.Body.Count - 2] = ilSwitch; // replace it, nothing else needs to be done!
                            result.Add(block);                           // except add it to the result, DOLT

                            scope.RemoveOrThrow(node);                   // Remove the item so that it is not picked up as content

                            // Pull in code of cases
                            ControlFlowNode fallTarget = null;
                            labelToCfNode.TryGetValue(fallLabel, out fallTarget);

                            HashSet <ControlFlowNode> frontiers = new HashSet <ControlFlowNode>();
                            if (fallTarget != null)
                            {
                                frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new[] { fallTarget }));
                            }

                            foreach (ILLabel condLabel in fswitch.CaseExpressions.Select(x => x.Value))
                            {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);
                                if (condTarget != null)
                                {
                                    frontiers.UnionWith(condTarget.DominanceFrontier.Except(new[] { condTarget }));
                                }
                            }
                            for (int i = 0; i < fswitch.CaseExpressions.Count; i++)
                            {
                                ILLabel condLabel = fswitch.CaseExpressions[i].Value;

                                // Find or create new case block
                                ILSwitch.ILCase caseBlock = ilSwitch.Cases.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
                                if (caseBlock == null)
                                {
                                    caseBlock = new ILSwitch.ILCase()
                                    {
                                        Values    = new List <ILExpression>(),
                                        EntryGoto = new ILExpression(GMCode.B, condLabel)
                                    };
                                    ilSwitch.Cases.Add(caseBlock);

                                    ControlFlowNode condTarget = null;
                                    labelToCfNode.TryGetValue(condLabel, out condTarget);
                                    if (condTarget != null && !frontiers.Contains(condTarget))
                                    {
                                        HashSet <ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
                                        scope.ExceptWith(content);
                                        foreach (var con in FindConditions(content, condTarget))
                                        {
                                            caseBlock.Body.Add(con);
                                        }
                                        //   caseBlock.Body.AddRange(FindConditions(content, condTarget));
                                        // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                        caseBlock.Body.Add(new ILBasicBlock()
                                        {
                                            Body =
                                            {
                                                ILLabel.Generate("SwitchBreak",            (int)nextLabelIndex++),
                                                new ILExpression(GMCode.LoopOrSwitchBreak, null)
                                            }
                                        });
                                    }
                                }
                                caseBlock.Values.Add(fswitch.CaseExpressions[i].Key);
                            }

                            // Heuristis to determine if we want to use fallthough as default case
                            if (fallTarget != null && !frontiers.Contains(fallTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, fallTarget);
                                if (content.Any())
                                {
                                    var caseBlock = new ILSwitch.ILCase()
                                    {
                                        EntryGoto = new ILExpression(GMCode.B, fallLabel)
                                    };
                                    ilSwitch.Cases.Add(caseBlock);
                                    block.Body.RemoveTail(GMCode.B);

                                    scope.ExceptWith(content);
                                    foreach (var con in FindConditions(content, fallTarget))
                                    {
                                        caseBlock.Body.Add(con);
                                    }

                                    // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                    caseBlock.Body.Add(new ILBasicBlock()
                                    {
                                        Body =
                                        {
                                            ILLabel.Generate("SwitchBreak",            (int)nextLabelIndex++),
                                            new ILExpression(GMCode.LoopOrSwitchBreak, null)
                                        }
                                    });
                                }
                            }
                        }
                        //   Debug.Assert((block.Body.First() as ILLabel).Name != "L1938");
                        // Two-way branch
                        ILLabel trueLabel;
                        ILLabel falseLabel;
                        IList <ILExpression> condExprs;
                        if (block.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExprs, out falseLabel) && // be sure to invert this condition
                            condExprs.Count > 0)     // its resolved
                        {
                            ILExpression   condExpr = condExprs[0];
                            IList <ILNode> body     = block.Body;
                            // this is a simple condition, skip anything short curiket for now
                            // Match a condition patern
                            // Convert the brtrue to ILCondition
                            ILCondition ilCond = new ILCondition()
                            {
                                Condition = condExpr, //code == GMCode.Bf ? condExpr : condExpr.NegateCondition(),
                                TrueBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(GMCode.B, trueLabel)
                                },
                                FalseBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(GMCode.B, falseLabel)
                                }
                            };
                            block.Body.RemoveTail(GMCode.Bt, GMCode.B);
                            block.Body.Add(ilCond);
                            result.Add(block);

                            // Remove the item immediately so that it is not picked up as content
                            scope.RemoveOrThrow(node);

                            ControlFlowNode trueTarget = null;
                            labelToCfNode.TryGetValue(trueLabel, out trueTarget);
                            ControlFlowNode falseTarget = null;
                            labelToCfNode.TryGetValue(falseLabel, out falseTarget);

                            // Pull in the conditional code
                            if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
                                scope.ExceptWith(content);
                                foreach (var con in FindConditions(content, trueTarget))
                                {
                                    ilCond.TrueBlock.Body.Add(con);
                                }
                            }
                            if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
                                scope.ExceptWith(content);
                                foreach (var con in FindConditions(content, falseTarget))
                                {
                                    ilCond.FalseBlock.Body.Add(con);
                                }
                            }
                        }
                    }

                    // Add the node now so that we have good ordering
                    if (scope.Contains(node))
                    {
                        result.Add((ILNode)node.UserData);
                        scope.Remove(node);
                    }
                }

                // depth-first traversal of dominator tree
                for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--)
                {
                    agenda.Push(node.DominatorTreeChildren[i]);
                }
            }

            // Add whatever is left
            foreach (var node in scope)
            {
                result.Add((ILNode)node.UserData);
            }

            return(result);
        }
コード例 #12
0
ファイル: LoopAndConditions.cs プロジェクト: WarlockD/GMdsam
        List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode)
        {
            List<ILNode> result = new List<ILNode>();

            // Do not modify entry data
            scope = new HashSet<ControlFlowNode>(scope);

            Stack<ControlFlowNode> agenda = new Stack<ControlFlowNode>();
            agenda.Push(entryNode);
            while (agenda.Count > 0)
            {
                ControlFlowNode node = agenda.Pop();

                // Find a block that represents a simple condition
                if (scope.Contains(node))
                {

                    ILBasicBlock block = (ILBasicBlock)node.UserData;
                   
                    {
                        IList<ILExpression> conditions;
                        ILLabel fallLabel;
                        // Switch
                        FakeSwitch fswitch;
                        if (block.MatchLastAndBr(GMCode.Switch, out fswitch, out conditions, out fallLabel))
                        {
                            ILSwitch ilSwitch = new ILSwitch() { Condition = fswitch.SwitchExpression };
                            block.Body[block.Body.Count - 2] = ilSwitch; // replace it, nothing else needs to be done!
                            result.Add(block); // except add it to the result, DOLT
                           
                            scope.RemoveOrThrow(node);// Remove the item so that it is not picked up as content

                            // Pull in code of cases
                            ControlFlowNode fallTarget = null;
                            labelToCfNode.TryGetValue(fallLabel, out fallTarget);

                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
                            if (fallTarget != null)
                                frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new[] { fallTarget }));

                            foreach (ILLabel condLabel in fswitch.CaseExpressions.Select(x => x.Value))
                            {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);
                                if (condTarget != null)
                                    frontiers.UnionWith(condTarget.DominanceFrontier.Except(new[] { condTarget }));
                            }
                            for (int i = 0; i < fswitch.CaseExpressions.Count; i++)
                            {
                                ILLabel condLabel = fswitch.CaseExpressions[i].Value;

                                // Find or create new case block
                                ILSwitch.ILCase caseBlock = ilSwitch.Cases.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
                                if (caseBlock == null)
                                {
                                    caseBlock = new ILSwitch.ILCase()
                                    {
                                        Values = new List<ILExpression>(),
                                        EntryGoto = new ILExpression(GMCode.B, condLabel)
                                    };
                                    ilSwitch.Cases.Add(caseBlock);

                                    ControlFlowNode condTarget = null;
                                    labelToCfNode.TryGetValue(condLabel, out condTarget);
                                    if (condTarget != null && !frontiers.Contains(condTarget))
                                    {
                                        HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
                                        scope.ExceptWith(content);
                                        foreach (var con in FindConditions(content, condTarget)) caseBlock.Body.Add(con);
                                        //   caseBlock.Body.AddRange(FindConditions(content, condTarget));
                                        // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                        caseBlock.Body.Add(new ILBasicBlock()
                                        {
                                            Body = {
                                                ILLabel.Generate("SwitchBreak" ,(int)nextLabelIndex++),
                                                new ILExpression(GMCode.LoopOrSwitchBreak, null)
                                            }
                                        });
                                    }
                                }
                                caseBlock.Values.Add(fswitch.CaseExpressions[i].Key);
                            }

                            // Heuristis to determine if we want to use fallthough as default case
                            if (fallTarget != null && !frontiers.Contains(fallTarget))
                            {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, fallTarget);
                                if (content.Any())
                                {
                                    var caseBlock = new ILSwitch.ILCase() { EntryGoto = new ILExpression(GMCode.B, fallLabel) };
                                    ilSwitch.Cases.Add(caseBlock);
                                    block.Body.RemoveTail(GMCode.B);

                                    scope.ExceptWith(content);
                                    foreach (var con in FindConditions(content, fallTarget)) caseBlock.Body.Add(con);
                                    
                                    // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                    caseBlock.Body.Add(new ILBasicBlock()
                                    { 
                                        Body = {
                                            ILLabel.Generate("SwitchBreak" ,(int)nextLabelIndex++),
                                            new ILExpression(GMCode.LoopOrSwitchBreak, null)
                                        }
                                    });
                                }
                            }
                        }
                     //   Debug.Assert((block.Body.First() as ILLabel).Name != "L1938");
                        // Two-way branch
                        ILLabel trueLabel;
                        ILLabel falseLabel;
                        IList<ILExpression> condExprs;
                        if (block.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExprs, out falseLabel) // be sure to invert this condition
                            && condExprs.Count > 0)  // its resolved
                        {
 
                            ILExpression condExpr = condExprs[0];
                            IList<ILNode> body = block.Body;
                            // this is a simple condition, skip anything short curiket for now
                            // Match a condition patern
                            // Convert the brtrue to ILCondition
                            ILCondition ilCond = new ILCondition()
                            {
                                Condition = condExpr, //code == GMCode.Bf ? condExpr : condExpr.NegateCondition(),
                                TrueBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, trueLabel) },
                                FalseBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, falseLabel) }
                            };
                            block.Body.RemoveTail(GMCode.Bt, GMCode.B);
                            block.Body.Add(ilCond);
                            result.Add(block);

                            // Remove the item immediately so that it is not picked up as content
                            scope.RemoveOrThrow(node);

                            ControlFlowNode trueTarget = null;
                            labelToCfNode.TryGetValue(trueLabel, out trueTarget);
                            ControlFlowNode falseTarget = null;
                            labelToCfNode.TryGetValue(falseLabel, out falseTarget);
   
                            // Pull in the conditional code
                            if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget))
                            {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
                                scope.ExceptWith(content);
                                foreach (var con in FindConditions(content, trueTarget)) ilCond.TrueBlock.Body.Add(con);
                            }
                            if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget))
                            {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
                                scope.ExceptWith(content);
                                foreach (var con in FindConditions(content, falseTarget)) ilCond.FalseBlock.Body.Add(con);
                            }
                       


                        }
                    }

                    // Add the node now so that we have good ordering
                    if (scope.Contains(node))
                    {
                        result.Add((ILNode)node.UserData);
                        scope.Remove(node);
                    }
                }

                // depth-first traversal of dominator tree
                for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--)
                {
                    agenda.Push(node.DominatorTreeChildren[i]);
                }
            }

            // Add whatever is left
            foreach (var node in scope)
            {
                result.Add((ILNode)node.UserData);
            }

            return result;
        }
コード例 #13
0
        List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode)
        {
            List<ILNode> result = new List<ILNode>();

            // Do not modify entry data
            scope = new HashSet<ControlFlowNode>(scope);

            HashSet<ControlFlowNode> agenda  = new HashSet<ControlFlowNode>();
            agenda.Add(entryNode);
            while(agenda.Any()) {
                ControlFlowNode node = agenda.First();
                // Attempt for a good order
                while(agenda.Contains(node.ImmediateDominator)) {
                    node = node.ImmediateDominator;
                }
                agenda.Remove(node);

                // Find a block that represents a simple condition
                if (scope.Contains(node)) {

                    ILBasicBlock block = node.UserData as ILBasicBlock;

                    if (block != null && block.Body.Count == 1) {

                        ILExpression condBranch = block.Body[0] as ILExpression;

                        // Switch
                        if (condBranch != null && condBranch.Operand is ILLabel[] && condBranch.Arguments.Count > 0) {

                            ILLabel[] caseLabels = (ILLabel[])condBranch.Operand;

                            // The labels will not be used - kill them
                            condBranch.Operand = null;

                            ILSwitch ilSwitch = new ILSwitch() {
                                Condition = condBranch,
                                DefaultGoto = block.FallthoughGoto
                            };
                            result.Add(new ILBasicBlock() {
                                EntryLabel = block.EntryLabel,  // Keep the entry label
                                Body = { ilSwitch }
                            });

                            // Remove the item so that it is not picked up as content
                            if (!scope.Remove(node))
                                throw new Exception("Item is not in set");

                            // Pull in code of cases
                            ControlFlowNode fallTarget = null;
                            labelToCfNode.TryGetValue((ILLabel)block.FallthoughGoto.Operand, out fallTarget);

                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
                            if (fallTarget != null)
                                frontiers.UnionWith(fallTarget.DominanceFrontier);

                            foreach(ILLabel condLabel in caseLabels) {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);
                                if (condTarget != null)
                                    frontiers.UnionWith(condTarget.DominanceFrontier);
                            }

                            foreach(ILLabel condLabel in caseLabels) {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);

                                ILBlock caseBlock = new ILBlock() {
                                    EntryGoto = new ILExpression(ILCode.Br, condLabel)
                                };
                                if (condTarget != null && !frontiers.Contains(condTarget)) {
                                    HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
                                    scope.ExceptWith(content);
                                    caseBlock.Body.AddRange(FindConditions(content, condTarget));
                                }
                                ilSwitch.CaseBlocks.Add(caseBlock);
                            }
                        }

                        // Two-way branch
                        ILExpression branchExpr = null;
                        ILLabel trueLabel = null;
                        ILLabel falseLabel = null;
                        if(IsConditionalBranch(block, ref branchExpr, ref trueLabel, ref falseLabel)) {

                            // The branch label will not be used - kill it
                            branchExpr.Operand = null;

                            // Convert the basic block to ILCondition
                            ILCondition ilCond = new ILCondition() {
                                Condition  = branchExpr,
                                TrueBlock  = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) },
                                FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) }
                            };
                            result.Add(new ILBasicBlock() {
                                    EntryLabel = block.EntryLabel,  // Keep the entry label
                                    Body = { ilCond }
                            });

                            // Remove the item immediately so that it is not picked up as content
                            if (!scope.Remove(node))
                                throw new Exception("Item is not in set");

                            ControlFlowNode trueTarget = null;
                            labelToCfNode.TryGetValue(trueLabel, out trueTarget);
                            ControlFlowNode falseTarget = null;
                            labelToCfNode.TryGetValue(falseLabel, out falseTarget);

                            // Pull in the conditional code
                            HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
                            if (trueTarget != null)
                                frontiers.UnionWith(trueTarget.DominanceFrontier);
                            if (falseTarget != null)
                                frontiers.UnionWith(falseTarget.DominanceFrontier);

                            if (trueTarget != null && !frontiers.Contains(trueTarget)) {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
                                scope.ExceptWith(content);
                                ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget));
                            }
                            if (falseTarget != null && !frontiers.Contains(falseTarget)) {
                                HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
                                scope.ExceptWith(content);
                                ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget));
                            }

                            if (scope.Count == 0) {
                                // We have removed the whole scope - eliminte one of the condition bodies
                                int trueSize = ilCond.TrueBlock.GetSelfAndChildrenRecursive<ILNode>().Count();
                                int falseSize = ilCond.FalseBlock.GetSelfAndChildrenRecursive<ILNode>().Count();

                                // The block are protected
                                Debug.Assert(ilCond.TrueBlock.EntryGoto != null);
                                Debug.Assert(ilCond.FalseBlock.EntryGoto != null);

                                if (falseSize > trueSize) {
                                    // Move the false body out
                                    result.AddRange(ilCond.FalseBlock.Body);
                                    ilCond.FalseBlock.Body.Clear();
                                } else {
                                    // Move the true body out
                                    result.AddRange(ilCond.TrueBlock.Body);
                                    ilCond.TrueBlock.Body.Clear();
                                }
                            }

                            // If true body is empty, swap bodies.
                            // Might happend because there was not any to start with or we moved it out.
                            if (ilCond.TrueBlock.Body.Count == 0 && ilCond.FalseBlock.Body.Count > 0) {
                                ILBlock tmp = ilCond.TrueBlock;
                                ilCond.TrueBlock = ilCond.FalseBlock;
                                ilCond.FalseBlock = tmp;
                                ilCond.Condition = new ILExpression(ILCode.LogicNot, null, ilCond.Condition);
                            }
                        }
                    }

                    // Add the node now so that we have good ordering
                    if (scope.Contains(node)) {
                        result.Add((ILNode)node.UserData);
                        scope.Remove(node);
                    }
                }

                // Using the dominator tree should ensure we find the the widest loop first
                foreach(var child in node.DominatorTreeChildren) {
                    agenda.Add(child);
                }
            }

            // Add whatever is left
            foreach(var node in scope) {
                result.Add((ILNode)node.UserData);
            }

            return result;
        }
コード例 #14
0
        List <ILNode> FindConditions(HashSet <ControlFlowNode> scope, ControlFlowNode entryNode)
        {
            List <ILNode> result = new List <ILNode>();

            // Do not modify entry data
            scope = new HashSet <ControlFlowNode>(scope);

            Stack <ControlFlowNode> agenda = new Stack <ControlFlowNode>();

            agenda.Push(entryNode);
            while (agenda.Count > 0)
            {
                ControlFlowNode node = agenda.Pop();

                // Find a block that represents a simple condition
                if (scope.Contains(node))
                {
                    ILBasicBlock block = (ILBasicBlock)node.UserData;

                    {
                        // Switch
                        ILLabel[]    caseLabels;
                        ILExpression switchArg;
                        ILLabel      fallLabel;
                        if (block.MatchLastAndBr(ILCode.Switch, out caseLabels, out switchArg, out fallLabel))
                        {
                            // Replace the switch code with ILSwitch
                            ILSwitch ilSwitch = new ILSwitch()
                            {
                                Condition = switchArg
                            };
                            block.Body.RemoveTail(ILCode.Switch, ILCode.Br);
                            block.Body.Add(ilSwitch);
                            block.Body.Add(new ILExpression(ILCode.Br, fallLabel));
                            result.Add(block);

                            // Remove the item so that it is not picked up as content
                            scope.RemoveOrThrow(node);

                            // Find the switch offset
                            int addValue = 0;
                            List <ILExpression> subArgs;
                            if (ilSwitch.Condition.Match(ILCode.Sub, out subArgs) && subArgs[1].Match(ILCode.Ldc_I4, out addValue))
                            {
                                ilSwitch.Condition = subArgs[0];
                            }

                            // Pull in code of cases
                            ControlFlowNode fallTarget = null;
                            labelToCfNode.TryGetValue(fallLabel, out fallTarget);

                            HashSet <ControlFlowNode> frontiers = new HashSet <ControlFlowNode>();
                            if (fallTarget != null)
                            {
                                frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new [] { fallTarget }));
                            }

                            foreach (ILLabel condLabel in caseLabels)
                            {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);
                                if (condTarget != null)
                                {
                                    frontiers.UnionWith(condTarget.DominanceFrontier.Except(new [] { condTarget }));
                                }
                            }

                            for (int i = 0; i < caseLabels.Length; i++)
                            {
                                ILLabel condLabel = caseLabels[i];

                                // Find or create new case block
                                ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
                                if (caseBlock == null)
                                {
                                    caseBlock = new ILSwitch.CaseBlock()
                                    {
                                        Values    = new List <int>(),
                                        EntryGoto = new ILExpression(ILCode.Br, condLabel)
                                    };
                                    ilSwitch.CaseBlocks.Add(caseBlock);

                                    ControlFlowNode condTarget = null;
                                    labelToCfNode.TryGetValue(condLabel, out condTarget);
                                    if (condTarget != null && !frontiers.Contains(condTarget))
                                    {
                                        HashSet <ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
                                        scope.ExceptWith(content);
                                        caseBlock.Body.AddRange(FindConditions(content, condTarget));
                                        // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                        caseBlock.Body.Add(new ILBasicBlock()
                                        {
                                            Body =
                                            {
                                                new ILLabel()
                                                {
                                                    Name = "SwitchBreak_" + (nextLabelIndex++)
                                                },
                                                new ILExpression(ILCode.LoopOrSwitchBreak, null)
                                            }
                                        });
                                    }
                                }
                                caseBlock.Values.Add(i + addValue);
                            }

                            // Heuristis to determine if we want to use fallthough as default case
                            if (fallTarget != null && !frontiers.Contains(fallTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, fallTarget);
                                if (content.Any())
                                {
                                    var caseBlock = new ILSwitch.CaseBlock()
                                    {
                                        EntryGoto = new ILExpression(ILCode.Br, fallLabel)
                                    };
                                    ilSwitch.CaseBlocks.Add(caseBlock);
                                    block.Body.RemoveTail(ILCode.Br);

                                    scope.ExceptWith(content);
                                    caseBlock.Body.AddRange(FindConditions(content, fallTarget));
                                    // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                    caseBlock.Body.Add(new ILBasicBlock()
                                    {
                                        Body =
                                        {
                                            new ILLabel()
                                            {
                                                Name = "SwitchBreak_" + (nextLabelIndex++)
                                            },
                                            new ILExpression(ILCode.LoopOrSwitchBreak, null)
                                        }
                                    });
                                }
                            }
                        }

                        // Two-way branch
                        ILExpression condExpr;
                        ILLabel      trueLabel;
                        ILLabel      falseLabel;
                        if (block.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
                        {
                            // Swap bodies since that seems to be the usual C# order
                            ILLabel temp = trueLabel;
                            trueLabel  = falseLabel;
                            falseLabel = temp;
                            condExpr   = new ILExpression(ILCode.LogicNot, null, condExpr);

                            // Convert the brtrue to ILCondition
                            ILCondition ilCond = new ILCondition()
                            {
                                Condition = condExpr,
                                TrueBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(ILCode.Br, trueLabel)
                                },
                                FalseBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(ILCode.Br, falseLabel)
                                }
                            };
                            block.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
                            block.Body.Add(ilCond);
                            result.Add(block);

                            // Remove the item immediately so that it is not picked up as content
                            scope.RemoveOrThrow(node);

                            ControlFlowNode trueTarget = null;
                            labelToCfNode.TryGetValue(trueLabel, out trueTarget);
                            ControlFlowNode falseTarget = null;
                            labelToCfNode.TryGetValue(falseLabel, out falseTarget);

                            // Pull in the conditional code
                            if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
                                scope.ExceptWith(content);
                                ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget));
                            }
                            if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
                                scope.ExceptWith(content);
                                ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget));
                            }
                        }
                    }

                    // Add the node now so that we have good ordering
                    if (scope.Contains(node))
                    {
                        result.Add((ILNode)node.UserData);
                        scope.Remove(node);
                    }
                }

                // depth-first traversal of dominator tree
                for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--)
                {
                    agenda.Push(node.DominatorTreeChildren[i]);
                }
            }

            // Add whatever is left
            foreach (var node in scope)
            {
                result.Add((ILNode)node.UserData);
            }

            return(result);
        }
コード例 #15
0
        public JSSwitchStatement TranslateNode(ILSwitch swtch)
        {
            var condition = TranslateNode(swtch.Condition);
            var conditionType = condition.GetExpectedType(TypeSystem);
            var result = new JSSwitchStatement(condition);

            Blocks.Push(result);

            result.Cases.AddRange(
                (from cb in swtch.CaseBlocks select TranslateNode(cb, conditionType))
            );

            Blocks.Pop();

            return result;
        }
コード例 #16
0
        public Dictionary <int, EventRegistration[]> DecompileEventMappings(string fullTypeName)
        {
            var            result = new Dictionary <int, EventRegistration[]>();
            TypeDefinition type   = this.assembly.MainModule.GetType(fullTypeName);

            if (type == null)
            {
                return(result);
            }

            MethodDefinition def = null;

            foreach (var method in type.Methods)
            {
                if (method.Name == "System.Windows.Markup.IComponentConnector.Connect")
                {
                    def = method;
                    break;
                }
            }

            if (def == null)
            {
                return(result);
            }

            // decompile method and optimize the switch
            ILBlock      ilMethod   = new ILBlock();
            ILAstBuilder astBuilder = new ILAstBuilder();

            ilMethod.Body = astBuilder.Build(def, true);
            ILAstOptimizer optimizer = new ILAstOptimizer();
            var            context   = new DecompilerContext(type.Module)
            {
                CurrentMethod = def, CurrentType = type
            };

            optimizer.Optimize(context, ilMethod, ILAstOptimizationStep.RemoveRedundantCode3);

            ILSwitch    ilSwitch  = ilMethod.Body.OfType <ILSwitch>().FirstOrDefault();
            ILCondition condition = ilMethod.Body.OfType <ILCondition>().FirstOrDefault();

            if (ilSwitch != null)
            {
                foreach (var caseBlock in ilSwitch.CaseBlocks)
                {
                    if (caseBlock.Values == null)
                    {
                        continue;
                    }
                    var events = FindEvents(caseBlock);
                    foreach (int id in caseBlock.Values)
                    {
                        result.Add(id, events);
                    }
                }
            }
            else if (condition != null)
            {
                result.Add(1, FindEvents(condition.FalseBlock));
            }

            return(result);
        }
コード例 #17
0
ファイル: LoopsAndConditions.cs プロジェクト: sq/ILSpy-JSIL
		/// <summary>
		/// Responsible for detecting switch cases with values that are actually also the default case
		/// </summary>
		static void AnointDefaultSwitchCases (ILSwitch swtch) {
			var defaultCase = swtch.CaseBlocks.FirstOrDefault((cse) => cse.IsDefault);
			if (defaultCase == null)
				return;

			var lastBlock = defaultCase.Body.LastOrDefault() as ILBasicBlock;
			if (
				(lastBlock != null) &&
				(lastBlock.Body.Count == 2) &&
				(lastBlock.Body[0] is ILLabel) &&
				(lastBlock.Body[1] is ILExpression) &&
				(((ILExpression)lastBlock.Body[1]).Code == ILCode.LoopOrSwitchBreak)
			) {
				// This is a delegating default case. Ensure the target is another case in this switch block.
				var targetCase = swtch.CaseBlocks.FirstOrDefault(
					(cse) => (
						(cse.EntryGoto.Operand == defaultCase.EntryGoto.Operand) &&
						(cse != defaultCase)
					)
				);

				if (targetCase != null) {
					// The target is another case in this switch block, so fold the current case into that one.
					swtch.CaseBlocks.Remove(defaultCase);
					targetCase.IsDefault = true;
				}
			}
		}
コード例 #18
0
		List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode)
		{
			List<ILNode> result = new List<ILNode>();
			
			// Do not modify entry data
			scope = new HashSet<ControlFlowNode>(scope);
			
			Stack<ControlFlowNode> agenda  = new Stack<ControlFlowNode>();
			agenda.Push(entryNode);
			while(agenda.Count > 0) {
				ControlFlowNode node = agenda.Pop();
				
				// Find a block that represents a simple condition
				if (scope.Contains(node)) {
					
					ILBasicBlock block = (ILBasicBlock)node.UserData;
					
					{
						// Switch
						ILLabel[] caseLabels;
						ILExpression switchArg;
						ILLabel fallLabel;
						if (block.MatchLastAndBr(ILCode.Switch, out caseLabels, out switchArg, out fallLabel)) {
							
							// Replace the switch code with ILSwitch
							ILSwitch ilSwitch = new ILSwitch() { Condition = switchArg };
							block.Body.RemoveTail(ILCode.Switch, ILCode.Br);
							block.Body.Add(ilSwitch);
							block.Body.Add(new ILExpression(ILCode.Br, fallLabel));
							result.Add(block);

							// Remove the item so that it is not picked up as content
							scope.RemoveOrThrow(node);
							
							// Find the switch offset
							int addValue = 0;
							List<ILExpression> subArgs;
							if (ilSwitch.Condition.Match(ILCode.Sub, out subArgs) && subArgs[1].Match(ILCode.Ldc_I4, out addValue)) {
								ilSwitch.Condition = subArgs[0];
							}
							
							// Pull in code of cases
							ControlFlowNode fallTarget = null;
							labelToCfNode.TryGetValue(fallLabel, out fallTarget);
							
							HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
							if (fallTarget != null)
								frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new [] { fallTarget }));
							
							foreach(ILLabel condLabel in caseLabels) {
								ControlFlowNode condTarget = null;
								labelToCfNode.TryGetValue(condLabel, out condTarget);
								if (condTarget != null)
									frontiers.UnionWith(condTarget.DominanceFrontier.Except(new [] { condTarget }));
							}
							
							for (int i = 0; i < caseLabels.Length; i++) {
								ILLabel condLabel = caseLabels[i];
								
								// Find or create new case block
								ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
								if (caseBlock == null) {
									caseBlock = new ILSwitch.CaseBlock() {
										Values = new List<int>(),
										EntryGoto = new ILExpression(ILCode.Br, condLabel)
									};
									ilSwitch.CaseBlocks.Add(caseBlock);
									
									ControlFlowNode condTarget = null;
									labelToCfNode.TryGetValue(condLabel, out condTarget);
									if (condTarget != null && !frontiers.Contains(condTarget)) {
										HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
										scope.ExceptWith(content);
										caseBlock.Body.AddRange(FindConditions(content, condTarget));
										// Add explicit break which should not be used by default, but the goto removal might decide to use it
										caseBlock.Body.Add(new ILBasicBlock() {
											Body = {
												new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) },
												new ILExpression(ILCode.LoopOrSwitchBreak, null)
											}
										});
									}
								}
								caseBlock.Values.Add(i + addValue);
							}
							
							// Heuristis to determine if we want to use fallthough as default case
							if (fallTarget != null && !frontiers.Contains(fallTarget)) {
								HashSet<ControlFlowNode> content = FindDominatedNodes(scope, fallTarget);
								if (content.Any()) {
									var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, fallLabel) };
									ilSwitch.CaseBlocks.Add(caseBlock);
									block.Body.RemoveTail(ILCode.Br);
									
									scope.ExceptWith(content);
									caseBlock.Body.AddRange(FindConditions(content, fallTarget));
									// Add explicit break which should not be used by default, but the goto removal might decide to use it
									caseBlock.Body.Add(new ILBasicBlock() {
										Body = {
											new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) },
											new ILExpression(ILCode.LoopOrSwitchBreak, null)
										}
									});
								}
							}
						}
						
						// Two-way branch
						ILExpression condExpr;
						ILLabel trueLabel;
						ILLabel falseLabel;
						if(block.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
							
							// Swap bodies since that seems to be the usual C# order
							ILLabel temp = trueLabel;
							trueLabel = falseLabel;
							falseLabel = temp;
							condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
							
							// Convert the brtrue to ILCondition
							ILCondition ilCond = new ILCondition() {
								Condition  = condExpr,
								TrueBlock  = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) },
								FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) }
							};
							block.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
							block.Body.Add(ilCond);
							result.Add(block);
							
							// Remove the item immediately so that it is not picked up as content
							scope.RemoveOrThrow(node);
							
							ControlFlowNode trueTarget = null;
							labelToCfNode.TryGetValue(trueLabel, out trueTarget);
							ControlFlowNode falseTarget = null;
							labelToCfNode.TryGetValue(falseLabel, out falseTarget);
							
							// Pull in the conditional code
							if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget)) {
								HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
								scope.ExceptWith(content);
								ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget));
							}
							if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget)) {
								HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
								scope.ExceptWith(content);
								ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget));
							}
						}
					}
					
					// Add the node now so that we have good ordering
					if (scope.Contains(node)) {
						result.Add((ILNode)node.UserData);
						scope.Remove(node);
					}
				}

				// depth-first traversal of dominator tree
				for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--) {
					agenda.Push(node.DominatorTreeChildren[i]);
				}
			}
			
			// Add whatever is left
			foreach(var node in scope) {
				result.Add((ILNode)node.UserData);
			}
			
			return result;
		}
コード例 #19
0
        private void ProcessMethodDecencies(InterMethod method, ILNode node, List <InterGenericArgument> genericArgs)
        {
            if (node is ILBlock)
            {
                ILBlock block = node as ILBlock;

                foreach (ILNode n in block.Body)
                {
                    ProcessMethodDecencies(method, n, genericArgs);
                }
            }
            else if (node is ILBasicBlock)
            {
                ILBasicBlock block = node as ILBasicBlock;

                foreach (ILNode n in block.Body)
                {
                    ProcessMethodDecencies(method, n, genericArgs);
                }
            }
            else if (node is ILTryCatchBlock)
            {
                ILTryCatchBlock block = node as ILTryCatchBlock;

                foreach (ILNode n in block.TryBlock.Body)
                {
                    ProcessMethodDecencies(method, n, genericArgs);
                }
                if (block.FaultBlock != null)
                {
                    foreach (ILNode n in block.FaultBlock.Body)
                    {
                        ProcessMethodDecencies(method, n, genericArgs);
                    }
                }
                if (block.FinallyBlock != null)
                {
                    foreach (ILNode n in block.FinallyBlock.Body)
                    {
                        ProcessMethodDecencies(method, n, genericArgs);
                    }
                }
                foreach (var catchBlock in block.CatchBlocks)
                {
                    ((IResolver)this).Resolve(catchBlock.ExceptionType, genericArgs);
                    ProcessMethodDecencies(method, catchBlock, genericArgs);
                }
            }
            else if (node is ILExpression)
            {
                ILExpression e = node as ILExpression;

                foreach (var n in e.Arguments)
                {
                    ProcessMethodDecencies(method, n, genericArgs);
                }

                if ((e.Code == ILCode.Mkrefany) || (e.Code == ILCode.Refanyval))
                {
                    ((IResolver)this).Resolve(ClassNames.SystemTypedReference.ClassName);
                }

                if (e.Code == ILCode.Refanytype)
                {
                    ((IResolver)this).Resolve(ClassNames.SystemTypedReference.ClassName);
                    ((IResolver)this).Resolve(ClassNames.SystemRuntimeTypeHandle.ClassName);
                }

                if (e.Code == ILCode.Arglist)
                {
                    ((IResolver)this).Resolve(ClassNames.SystemRuntimeArgumentHandle.ClassName);
                }

                if (e.Code.IsExternalRealization())
                {
                    ((IResolver)this).Resolve(ClassNames.CIL2JavaVESInstructions.ClassName);
                }

                if (e.Code == ILCode.Ldc_Decimal)
                {
                    ((IResolver)this).Resolve(ClassNames.SystemDecimal.ClassNames);
                }

                if (e.Code == ILCode.Ldtoken)
                {
                    if (e.Operand is TypeReference)
                    {
                        ((IResolver)this).Resolve(ClassNames.SystemRuntimeTypeHandle.ClassName);
                    }
                    else if (e.Operand is FieldReference)
                    {
                        ((IResolver)this).Resolve(ClassNames.SystemRuntimeFieldHandle.ClassName);
                    }
                    else if (e.Operand is MethodReference)
                    {
                        ((IResolver)this).Resolve(ClassNames.SystemRuntimeMethodHandle.ClassName);
                    }
                }

                if (e.Operand is ILVariable)
                {
                    ((IResolver)this).Resolve(((ILVariable)e.Operand).Type, genericArgs);
                }
                if (e.Operand is TypeReference)
                {
                    ((IResolver)this).Resolve((TypeReference)e.Operand, genericArgs);
                }
                if (e.Operand is MethodReference)
                {
                    ((IResolver)this).Resolve((MethodReference)e.Operand, genericArgs);
                }
                if (e.Operand is FieldReference)
                {
                    InterField fld          = ((IResolver)this).Resolve((FieldReference)e.Operand, genericArgs);
                    bool       needAccessor = false;

                    if ((fld.IsPrivate) && (fld.DeclaringType != method.DeclaringType))
                    {
                        needAccessor = true;
                    }
                    else if ((fld.IsProtected) && (fld.DeclaringType != method.DeclaringType) &&
                             (!method.DeclaringType.IsSuper(fld.DeclaringType)))
                    {
                        needAccessor = true;
                    }

                    if (needAccessor)
                    {
                        switch (e.Code)
                        {
                        case ILCode.Ldflda:
                        case ILCode.Ldsflda:
                            if (fld.FieldType.IsValueType)
                            {
                                fld.DeclaringType.AddFieldAccessor(new FieldAccessor(FieldAccessorType.Getter, fld));
                            }
                            break;

                        case ILCode.Ldfld:
                        case ILCode.Ldsfld:
                            fld.DeclaringType.AddFieldAccessor(new FieldAccessor(FieldAccessorType.Getter, fld));
                            break;

                        case ILCode.Stfld:
                        case ILCode.Stsfld:
                            fld.DeclaringType.AddFieldAccessor(new FieldAccessor(FieldAccessorType.Setter, fld));
                            break;
                        }
                    }
                }

                InterType expected = null;
                InterType inferred = null;

                if (e.ExpectedType != null)
                {
                    expected = ((IResolver)this).Resolve(e.ExpectedType, genericArgs);
                }
                if (e.InferredType != null)
                {
                    inferred = ((IResolver)this).Resolve(e.InferredType, genericArgs);
                }

                if ((expected != null) && (expected.IsInterface) && (inferred != null) && (inferred.IsArray))
                {
                    ((IResolver)this).Resolve(ClassNames.ArraysInterfaceAdapterTypeName,
                                              new List <InterGenericArgument>()
                    {
                        new InterGenericArgument(GenericArgumentOwnerType.Type, 0, inferred.ElementType)
                    });
                }
            }
            else if (node is ILWhileLoop)
            {
                ILWhileLoop loop = node as ILWhileLoop;
                ProcessMethodDecencies(method, loop.Condition, genericArgs);
                ProcessMethodDecencies(method, loop.BodyBlock, genericArgs);
            }
            else if (node is ILCondition)
            {
                ILCondition cond = node as ILCondition;
                ProcessMethodDecencies(method, cond.Condition, genericArgs);
                ProcessMethodDecencies(method, cond.TrueBlock, genericArgs);
                ProcessMethodDecencies(method, cond.FalseBlock, genericArgs);
            }
            else if (node is ILSwitch)
            {
                ILSwitch sw = node as ILSwitch;
                ProcessMethodDecencies(method, sw.Condition, genericArgs);
                foreach (var c in sw.CaseBlocks)
                {
                    ProcessMethodDecencies(method, c, genericArgs);
                }
            }
            else if (node is ILFixedStatement)
            {
                ILFixedStatement fs = node as ILFixedStatement;
                foreach (var n in fs.Initializers)
                {
                    ProcessMethodDecencies(method, n, genericArgs);
                }
                ProcessMethodDecencies(method, fs.BodyBlock, genericArgs);
            }
        }