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("}"); }
protected virtual ILSwitch VisitSwitch(ILSwitch switchStatement) { foreach (var child in switchStatement.GetChildren()) { Visit(child); } return(switchStatement); }
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; }
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)) ); }
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; }
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); }
/// <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()); }
/// <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()); }
protected virtual ILSwitch VisitSwitch(ILSwitch switchStatement) { foreach (var child in switchStatement.GetChildren()) Visit(child); return switchStatement; }
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; }
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); }
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; }
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; }
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); }
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; }
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); }
/// <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; } } }
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; }
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); } }