void CreateSwitchExpresion(ILNode condition, List <ILNode> list, List <ILNode> body, ILBasicBlock head, int pos) { // we are in a case block, check if its the first block List <ILBasicBlock> caseBlocks = new List <ILBasicBlock>(); List <ILLabel> caseLabels = new List <ILLabel>(); ILExpression switchExpression = new ILExpression(GMCode.Switch, null); switchExpression.Arguments.Add(NodeToExpresion(condition)); // pop the switch condition ILBasicBlock current = head; ILLabel nextCase; ILLabel caseTrue; ILExpression fakeArgument; while (current.MatchLastAndBr(GMCode.Bt, out caseTrue, out fakeArgument, out nextCase)) { ILNode operand; if (!current.MatchAt(current.Body.Count - 4, GMCode.Push, out operand)) { throw new Exception("fix"); } if (!(operand is ILValue)) { throw new Exception("Can only handle constants right now"); } switchExpression.Arguments.Add(new ILExpression(GMCode.Case, caseTrue, NodeToExpresion(operand))); caseLabels.Add(caseTrue); body.Remove(current); current = labelToBasicBlock[nextCase]; } body.Insert(pos, head); var lastBlock = current; ILLabel fallLabel; if (!lastBlock.MatchSingle(GMCode.B, out fallLabel)) { throw new Exception("fix"); } current = labelToBasicBlock[fallLabel]; if (!current.MatchAt(1, GMCode.Popz)) { // has a default case // Side note, the LoopAndConditions figures out if we have a default case by checking // if the ending branch is linked to all the other case branches // so we don't need to do anything here // All this code is JUST for finding that popz that pops the condition out of the switch // if you don't care about it, you could just search though all the expresions and remove any and all // popz's I am beggining to think this is the right way to do it as I don't see any other uses // of popz's // Debug.Assert(false); BuildNextBlockData(); // build block chain, we need this for default and mabye case lookups // ok, this is why we DON'T want to remove redundent code as there is this empty // useless goto RIGHt after this that has the link to the finale case ILLabel nextBlockLabel = lastBlock.Body.First() as ILLabel; var uselessBlock = this.labelToNextBlock[nextBlockLabel]; ILLabel newFallLabel; if (!uselessBlock.MatchSingle(GMCode.B, out newFallLabel)) { throw new Exception("fix"); } current = labelToBasicBlock[newFallLabel]; if (!current.MatchAt(1, GMCode.Popz)) { throw new Exception("I have no idea where the popz is for this switch"); } } current.Body.RemoveAt(1); ILLabel lastBlockLabel = lastBlock.Body.First() as ILLabel; if (this.labelGlobalRefCount[lastBlockLabel] == 1) { body.Remove(lastBlockLabel); } switchExpression.Operand = caseLabels.ToArray(); list.Add(switchExpression); list.Add(new ILExpression(GMCode.B, fallLabel)); }
public static bool Match(this ILNode node, GMCode code) { ILExpression expr = node as ILExpression; return(expr != null && expr.Code == code); }
/// <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; // 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(GMCode.BadOp)) { current = n as ILTryCatchBlock; break; } } } return(null); } } else if (expr.Code == GMCode.BadOp) { 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); } ILWithStatement with = node as ILWithStatement; if (with != null) { if (with.Enviroment != null) { return(with.Enviroment); } else { return(Enter(with.Body, visitedNodes)); } } 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()); }