public int LabelCount(ILLabel l) { return(labelGlobalRefCount[l]); }
/// <summary> /// Group input into a set of blocks that can be later arbitraliby schufled. /// The method adds necessary branches to make control flow between blocks /// explicit and thus order independent. /// </summary> public static void SplitToBasicBlocks(ILBlock block) { int nextLabelIndex = 0; List <ILNode> basicBlocks = new List <ILNode>(); ILLabel entryLabel = block.Body.FirstOrDefault() as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++) }; ILBasicBlock basicBlock = new ILBasicBlock(); basicBlocks.Add(basicBlock); basicBlock.Body.Add(entryLabel); block.EntryGoto = new ILExpression(GMCode.B, entryLabel); if (block.Body.Count > 0) { if (block.Body[0] != entryLabel) { basicBlock.Body.Add(block.Body[0]); } for (int i = 1; i < block.Body.Count; i++) { ILNode lastNode = block.Body[i - 1]; ILNode currNode = block.Body[i]; // Start a new basic block if necessary if (currNode is ILLabel || lastNode.IsConditionalControlFlow() || lastNode.IsUnconditionalControlFlow()) { // Try to reuse the label ILLabel label = currNode as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++).ToString() }; // Terminate the last block if (!lastNode.IsUnconditionalControlFlow()) { // Explicit branch from one block to other basicBlock.Body.Add(new ILExpression(GMCode.B, label)); } // Start the new block basicBlock = new ILBasicBlock(); basicBlocks.Add(basicBlock); basicBlock.Body.Add(label); // Add the node to the basic block if (currNode != label) { basicBlock.Body.Add(currNode); } } else { basicBlock.Body.Add(currNode); } } } block.Body = basicBlocks; return; }
public bool SimplifyShortCircuit(IList <ILNode> body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); // Debug.Assert((head.Body[0] as ILLabel).Name != "Block_54"); ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; // Ok, since we have not changed out all the Bf's to Bt like in ILSpy, we have to do them seperately // as I am getting bugs in my wahhoo about it if ((head.MatchLastAndBr(GMCode.Bf, out falseLabel, out condExpr, out trueLabel) || head.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel)) && condExpr.Code != GMCode.Pop // its a terrtery so ignore it? ) // I saw this too { GMCode code = (head.Body[head.Body.Count - 2] as ILExpression).Code; for (int pass = 0; pass < 2; pass++) { // On the second pass, swap labels and negate expression of the first branch // It is slightly ugly, but much better then copy-pasting this whole block ILLabel nextLabel = (pass == 0) ? trueLabel : falseLabel; ILLabel otherLablel = (pass == 0) ? falseLabel : trueLabel; bool negate = (pass == 1); negate = GMCode.Bt == code ? !negate : negate; ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel]; ILExpression nextCondExpr; ILLabel nextTrueLablel; ILLabel nextFalseLabel; if (body.Contains(nextBasicBlock) && nextBasicBlock != head && labelGlobalRefCount[(ILLabel)nextBasicBlock.Body.First()] == 1 && (nextBasicBlock.MatchSingleAndBr(GMCode.Bf, out nextFalseLabel, out nextCondExpr, out nextTrueLablel) || nextBasicBlock.MatchSingleAndBr(GMCode.Bt, out nextTrueLablel, out nextCondExpr, out nextFalseLabel)) && nextCondExpr.Code != GMCode.Pop && // ugh (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel)) { // Debug.Assert(nextCondExpr.Arguments.Count != 2); // Create short cicuit branch ILExpression logicExpr; if (otherLablel == nextFalseLabel) { logicExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicAnd, negate ? new ILExpression(GMCode.Not, null, condExpr) : condExpr, nextCondExpr); } else { logicExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicOr, negate ? condExpr : new ILExpression(GMCode.Not, null, condExpr), nextCondExpr); } // head.Body.RemoveTail(GMCode.Bf, GMCode.B); head.Body.RemoveRange(head.Body.Count - 2, 2); head.Body.Add(new ILExpression(GMCode.Bf, nextFalseLabel, logicExpr)); head.Body.Add(new ILExpression(GMCode.B, nextTrueLablel)); // Remove the inlined branch from scope body.RemoveOrThrow(nextBasicBlock); return(true); } } } return(false); }
public ILBasicBlock LabelToBasicBlock(ILLabel l) { return(labelToBasicBlock[l]); }
public static bool MatchLastAndBr <T>(this ILBasicBlock bb, GMCode code, out T operand, out IList <ILExpression> args, out ILLabel brLabel) { if (bb.Body.ElementAtOrDefault(bb.Body.Count - 2).Match(code, out operand, out args) && bb.Body.LastOrDefault().Match(GMCode.B, out brLabel)) { return(true); } operand = default(T); args = null; brLabel = null; return(false); }
public static bool MatchCaseBlock(this ILBasicBlock bb, out ILExpression caseCondition, out ILLabel caseLabel, out ILLabel nextCase) { int dupType = 0; ILExpression pushSeq; ILExpression btExpresion; if (bb.Body.Count == 6 && bb.Body[0] is ILLabel && bb.Body[1].Match(GMCode.Dup, out dupType) && dupType == 0 && bb.Body[2].Match(GMCode.Push, out caseCondition) && bb.Body[3].Match(GMCode.Seq) && bb.MatchLastAndBr(GMCode.Bt, out caseLabel, out btExpresion, out nextCase) ) { return(true); } caseCondition = default(ILExpression); caseLabel = nextCase = default(ILLabel); return(false); }
public static bool MatchSingleAndBr <T>(this ILBasicBlock bb, GMCode code, out T operand, out ILExpression arg, out ILLabel brLabel) { { if (bb.Body.Count == 3 && bb.Body[0] is ILLabel && bb.Body[1].Match(code, out operand, out arg) && bb.Body[2].Match(GMCode.B, out brLabel)) { return(true); } } operand = default(T); arg = null; brLabel = null; return(false); }
public static bool MatchLastAndBr(this ILBasicBlock bb, GMCode code, out ILExpression arg, out ILLabel brLabel) { if (bb.Body.ElementAtOrDefault(bb.Body.Count - 2).Match(code, out arg) && bb.Body.LastOrDefault().Match(GMCode.B, out brLabel)) { return(true); } arg = default(ILExpression); brLabel = null; return(false); }
public static bool MatchSingleAndBr(this ILBasicBlock bb, GMCode code, out ILExpression arg, out ILLabel brLabel) { object filler; return(bb.MatchSingleAndBr <object>(code, out filler, out arg, out brLabel)); }
List <ILNode> BuildPreAst() { // Just convert instructions to ast streight List <ILNode> nodes = new List <ILNode>(); Dictionary <int, ILLabel> labels = new Dictionary <int, ILLabel>(); Func <Label, ILLabel> ConvertLabel = (Label l) => { ILLabel lookup; if (labels.TryGetValue(l.Address, out lookup)) { return(lookup); } lookup = new ILLabel() { Name = l.ToString(), UserData = l }; labels.Add(l.Address, lookup); return(lookup); }; foreach (var i in _method.Values) { // Debug.Assert(nodes.Count != 236); GMCode code = i.Code; object operand = i.Operand; int extra = i.Extra; if (i.Label != null) { nodes.Add(ConvertLabel(i.Label)); } ILExpression expr = null; switch (code) { case GMCode.Conv: continue; // ignore all Conv for now case GMCode.Call: // Since we have to resolve calls seperately and need expr = new ILExpression(GMCode.Call, operand as string); expr.Extra = extra; // need to know how many arguments we have break; case GMCode.Popz: expr = new ILExpression(code, null); break; case GMCode.Pop: // var define, so lets define it expr = new ILExpression(GMCode.Pop, BuildVar((int)operand, extra)); expr.Extra = extra; break; case GMCode.Push: if (i.Types[0] != GM_Type.Var) { expr = new ILExpression(GMCode.Push, OperandToIValue(operand, i.Types[0])); // simple constant } else { expr = new ILExpression(GMCode.Push, BuildVar((int)operand, extra)); // try to figure out the var); } expr.Extra = extra; break; case GMCode.Pushenv: // the asembler converted the positions to labels at the end of the push/pop enviroments expr = new ILExpression(GMCode.Pushenv, ConvertLabel(i.Operand as Label)); break; case GMCode.Popenv: expr = new ILExpression(GMCode.B, ConvertLabel(i.Operand as Label)); break; case GMCode.B: expr = new ILExpression(GMCode.B, ConvertLabel(i.Operand as Label)); break; case GMCode.Ret: expr = new ILExpression(code, null, new ILExpression(GMCode.Pop, null)); break; case GMCode.Bt: case GMCode.Bf: expr = new ILExpression(code, ConvertLabel(i.Operand as Label), new ILExpression(GMCode.Pop, null)); break; case GMCode.Dup: expr = new ILExpression(code, extra); // save the extra value for dups incase its dup eveything or just one // HackDebug(i, _method.Values); break; case GMCode.Exit: expr = new ILExpression(code, null); break; default: expr = new ILExpression(code, null); break; } expr.ILRanges.Add(new ILRange(i.Address, i.Address)); nodes.Add(expr); } return(nodes); }
void TestAndFixWierdLoop(List <ILNode> body, ILBasicBlock head, int pos) { object uvalue1; ILValue value2; ILLabel endLoop; ILLabel startLoop; ILExpression filler; //Debug.Assert((head.Body[0] as ILLabel).Name != "L36"); // Wierd one here. I ran accross this a few times and I think this is generated code // for events. Basicly, it pushes a constant on the stack and uses a repeat loop // however since I am not doing ANY kind of real stack/temporary analysis. I would have // to rewrite and add a bunch of code to get that to work and right now its only a few functions // Its easyer to build a while loop out of it and let the decompiler handle it rather than // build a more robust stack anilizer // ugh have to make a new block for it too, meh int headLen = head.Body.Count; if (head.MatchAt(headLen - 6, GMCode.Push, out uvalue1) && head.MatchAt(headLen - 5, GMCode.Dup) && head.MatchAt(headLen - 4, GMCode.Push, out value2) && head.MatchAt(headLen - 3, GMCode.Sle) && head.MatchLastAndBr(GMCode.Bt, out endLoop, out filler, out startLoop)) { // ok, lets rewrite the head so it makes sence ILLabel newLoopStart = NewJunkLoop(); ILVariable genVar = NewGeneratedVar(); List <ILNode> newHead = new List <ILNode>(); for (int ii = 0; ii <= headLen - 7; ii++) { newHead.Add(head.Body[ii]); // add the front of it including the sub part } newHead.Add(new ILExpression(GMCode.Push, uvalue1)); newHead.Add(new ILExpression(GMCode.Pop, genVar)); newHead.Add(new ILExpression(GMCode.B, newLoopStart)); ILBasicBlock newLoopBlock = new ILBasicBlock(); newLoopBlock.Body.Add(newLoopStart); newLoopBlock.Body.Add(new ILExpression(GMCode.Push, genVar)); newLoopBlock.Body.Add(new ILExpression(GMCode.Push, new ILValue(0))); newLoopBlock.Body.Add(new ILExpression(GMCode.Sgt, null)); newLoopBlock.Body.Add(new ILExpression(GMCode.Bf, endLoop, new ILExpression(GMCode.Pop, null))); newLoopBlock.Body.Add(new ILExpression(GMCode.B, startLoop)); head.Body = newHead; body.Add(newLoopBlock); // Now the hard part, we have to find the end bit for (int j = pos; j < body.Count; j++) { ILBasicBlock bj = body[j] as ILBasicBlock; ILLabel testEnd, testStart; ILValue subPart; int len = bj.Body.Count; // Debug.Assert((bj.Body[0] as ILLabel).Name != "L114"); if (bj.MatchLastAndBr(GMCode.Bt, out testStart, out filler, out testEnd) && testEnd == endLoop && testStart == startLoop && bj.MatchAt(len - 3, GMCode.Dup) && bj.MatchAt(len - 4, GMCode.Sub) && bj.MatchAt(len - 5, GMCode.Push, out subPart) ) { List <ILNode> list2 = new List <ILNode>(); for (int ii = 0; ii <= len - 6; ii++) { list2.Add(bj.Body[ii]); // add the front of it including the sub part } list2.Add(new ILExpression(GMCode.Push, genVar)); list2.Add(bj.Body[len - 5]); // add the sub part list2.Add(bj.Body[len - 4]); // add the sub part list2.Add(new ILExpression(GMCode.Pop, genVar)); // assign it list2.Add(new ILExpression(GMCode.B, newLoopStart)); // branch back to the start bj.Body = list2; // replace break; // all done, let it continue } } // Debug.Assert(false); // coudln't find the end block } }
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()); }