Status ProcessExpression(List <ILNode> list, ILBasicBlock head, int pos, Stack <ILNode> stack) { ILExpression e = head.Body[pos] as ILExpression; if (e == null) { list.Add(head.Body[pos]); return(Status.NoChangeAdded); } ILValue tempValue; ILVariable tempVar; switch (e.Code) { case GMCode.Push: tempValue = e.Operand as ILValue; tempVar = e.Operand as ILVariable; if (tempValue != null) { stack.Push(tempValue); } else if (tempVar != null) { ProcessVar(tempVar, stack); stack.Push(tempVar); } else { // block comes back as a push expression Debug.Assert(e.Arguments.Count > 0); stack.Push(e.Arguments[0]); } return(Status.AddedToStack); case GMCode.Pop: // convert to an assign { tempVar = e.Operand as ILVariable; Debug.Assert(tempVar != null); ILExpression expr = null; if (Dup1Seen) { expr = NodeToExpresion(stack.Pop()); // have to swap the assignment if a dup 1 was done } ProcessVar(tempVar, stack); e.Code = GMCode.Assign; e.Operand = null; e.Arguments.Add(NodeToExpresion(tempVar)); if (!Dup1Seen) { expr = NodeToExpresion(stack.Pop()); } e.Arguments.Add(expr); list.Add(e); return(Status.ChangedAdded); } case GMCode.Call: { if (e.Extra == -1) { list.Add(e); return(Status.NoChangeAdded); } // its already resolved //ILExpression call = new ILExpression(GMCode.Call, ) //ILCall call = new ILCall() { Name = e.Operand as string }; //for (int j = 0; j < e.Extra; j++) call.Arguments.Add(stack.Pop()); if (e.Extra > 0) { for (int j = 0; j < e.Extra; j++) { e.Arguments.Add(NodeToExpresion(stack.Pop())); } } e.Extra = -1; stack.Push(e); } return(Status.AddedToStack); case GMCode.Popz: { if (stack.Count == 0) { list.Add(e); // Debug.Assert(false); return(Status.ChangedAdded); } else { ILExpression call = stack.Peek() as ILExpression; if (call != null && call.Code == GMCode.Call) { stack.Pop(); list.Add(call); return(Status.ChangedAdded); } else { throw new Exception("popz on a non call?"); // return e; // else, ignore for switch } } } case GMCode.Bf: case GMCode.Bt: case GMCode.Ret: if (stack.Count > 0) { // Debug.Assert(stack.Count == 1); e.Arguments[0] = NodeToExpresion(stack.Pop()); if (stack.Count > 0) { foreach (var n in stack) { list.Add(new ILExpression(GMCode.Push, null, NodeToExpresion(n))); } } list.Add(e); return(Status.ChangedAdded); } else { list.Add(e); return(Status.NoChangeAdded); } case GMCode.B: case GMCode.Exit: if (stack.Count > 0) { foreach (var n in stack) { list.Add(new ILExpression(GMCode.Push, null, NodeToExpresion(n))); } } list.Add(e); return(Status.ChangedAdded); case GMCode.Dup: if ((int)e.Operand == 0) { stack.Push(stack.Peek()); // simple case return(Status.DupStack0); } else { // this is usally on an expression that uses a var multipual times so the instance and index is copyed // HOWEVER the stack may need to be swaped foreach (var n in stack.Reverse().ToArray()) { stack.Push(n); // copy the entire stack } Dup1Seen = true; // usally this is on an assignment += -= of an array or such return(Status.DupStack1); } default: // ok we handle an expression if (e.Code.isExpression()) { for (int j = 0; j < e.Code.GetPopDelta(); j++) { if (stack.Count > 0) { e.Arguments.Add(NodeToExpresion(stack.Pop())); } else { e.Arguments.Add(new ILExpression(GMCode.Pop, null)); } } e.Arguments.Reverse(); // till I fix it latter, sigh stack.Push(e); // push expressions back return(Status.AddedToStack); } else { list.Add(e); return(Status.NoChangeAdded); } } throw new Exception("Shouldn't get here?"); }
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)); }
/// <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()); }