From 12629a2670758a072362e6a49a02eb99099c352c Mon Sep 17 00:00:00 2001 From: WarlockD Date: Thu, 21 Apr 2016 11:41:09 -0500 Subject: [PATCH] DONE! Months of work finaly. This thing will extract all the srouce from Underatle 1.0 and decompile it. --- betteribttest/Dissasembler/BuildFullAst.cs | 385 ++++++++---------- betteribttest/Dissasembler/GotoRemoval.cs | 6 +- .../Dissasembler/LoopAndConditions.cs | 3 +- betteribttest/Dissasembler/Optimize.cs | 1 + betteribttest/Dissasembler/PaternMatching.cs | 7 +- betteribttest/FlowAnalysis/StackAnalysis.cs | 46 +-- betteribttest/GMContext.cs | 1 + betteribttest/Program.cs | 7 +- 8 files changed, 190 insertions(+), 266 deletions(-) diff --git a/betteribttest/Dissasembler/BuildFullAst.cs b/betteribttest/Dissasembler/BuildFullAst.cs index 431a4b3..533f172 100644 --- a/betteribttest/Dissasembler/BuildFullAst.cs +++ b/betteribttest/Dissasembler/BuildFullAst.cs @@ -11,7 +11,7 @@ class BuildFullAst { Dictionary labelGlobalRefCount = new Dictionary(); Dictionary labelToBasicBlock = new Dictionary(); - + GMContext context; ILBlock method; // TypeSystem typeSystem; @@ -38,10 +38,10 @@ public BuildFullAst(ILBlock method, GMContext context) void BuildNextBlockData() { labelToNextBlock = new Dictionary(); - for(int i=0;i < method.Body.Count-1; i++) + for (int i = 0; i < method.Body.Count - 1; i++) { ILBasicBlock bb = method.Body[i] as ILBasicBlock; - ILBasicBlock next = method.Body[i+1] as ILBasicBlock; + ILBasicBlock next = method.Body[i + 1] as ILBasicBlock; ILLabel label = (bb.Body.First() as ILLabel); labelToNextBlock[label] = next; } @@ -56,7 +56,7 @@ void ProcessVar(ILVariable v, Stack stack) if (v.isArray) v.Index = stack.Pop(); // get the index first v.Instance = stack.Pop(); // get the instance value = v.Instance as ILValue; - if(value != null && value.Value is int) + if (value != null && value.Value is int) { v.InstanceName = context.InstanceToString((int)value); } @@ -93,13 +93,13 @@ void CheckList(List node) Debug.Assert(list.Count == 0); } } - + enum Status { DetectedPosableCase, NoChangeAdded, ChangedAdded, - AddedToStack, + AddedToStack, DupStack0, DupStack1 } @@ -119,7 +119,7 @@ Status ProcessExpression(List list, ILBasicBlock head, int pos, Stack list, ILBasicBlock head, int pos, Stack list, ILBasicBlock head, int pos, Stack list, ILBasicBlock head, int pos, Stack 0) { - // Debug.Assert(stack.Count == 1); + // Debug.Assert(stack.Count == 1); e.Arguments[0] = NodeToExpresion(stack.Pop()); - if(stack.Count >0) + 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 + } + else { list.Add(e); return Status.NoChangeAdded; @@ -224,7 +225,7 @@ Status ProcessExpression(List list, ILBasicBlock head, int pos, Stack list, ILBasicBlock head, int pos, Stack list, List body, ILBasicBlock head, int pos) + { + // we are in a case block, check if its the first block + + List caseBlocks = new List(); + List caseLabels = new List(); + 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)); + } + int generated_var_count = 0; + int loop_junk_block = 0; + ILVariable NewGeneratedVar() + { + return new ILVariable() { Name = "gen_" + generated_var_count++, Instance = new ILValue(-1), InstanceName = "self", isResolved = true }; + } + ILLabel NewJunkLoop() + { + return new ILLabel() { Name = "gen_block_" + loop_junk_block++ }; + } + void TestAndFixWierdLoop(List 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 newHead = new List(); + 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 list2 = new List(); + 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 ProcessExpressions(List body, ILBasicBlock head, int pos) { Stack stack = new Stack(); List list = new List(); Dup1Seen = false; + TestAndFixWierdLoop(body, head, pos); + + for (int i = 0; i < head.Body.Count; i++) { if (stack.Count == 1 && @@ -276,62 +419,7 @@ void ProcessExpressions(List body, ILBasicBlock head, int pos) head.MatchAt(i + 2, GMCode.Seq) && head.MatchAt(i + 3, GMCode.Bt)) { - // we are in a case block, check if its the first block - - List caseBlocks = new List(); - List caseLabels = new List(); - ILExpression switchExpression = new ILExpression(GMCode.Switch, null); - switchExpression.Arguments.Add(NodeToExpresion(stack.Pop())); // 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)); + CreateSwitchExpresion(stack.Pop(), list, body, head, pos); break; // we are done with this block @@ -342,159 +430,8 @@ void ProcessExpressions(List body, ILBasicBlock head, int pos) } } - - head.Body = list; - } - public bool ProcessExpressions2(IList body, ILBasicBlock head, int pos) - { - - ILLabel label = head.Body[0] as ILLabel; - // Debug.Assert(label.Name != "Block_0"); - // Debug.Assert(label.Name != "L16"); - List list = new List(); // New body - Stack stack = new Stack(); - ILValue tempValue; - ILVariable tempVar; - bool Dup1Seen = false; - bool possableCase = false; - int oldCount = head.Body.Count; - for (int i = 0; i < oldCount; i++) - { - ILExpression e = head.Body[i] as ILExpression; - ILNode nexpr = null; - if (e == null) - { - list.Add(head.Body[i]); - continue; // skip labels or wierd stuff - } - switch (e.Code) - { - case GMCode.Push: - tempValue = e.Operand as ILValue; - if (tempValue != null) { stack.Push(tempValue); break; } - tempVar = e.Operand as ILVariable; - 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]); - } - break; - case GMCode.Pop: // convert to an assign - tempVar = e.Operand as ILVariable; - Debug.Assert(tempVar != null); - ProcessVar(tempVar, stack); - e.Code = GMCode.Assign; - e.Operand = null; - e.Arguments.Add(NodeToExpresion(tempVar)); - e.Arguments.Add(NodeToExpresion(stack.Pop())); - nexpr = e; - Dup1Seen = false; - break; - case GMCode.Call: - { - if (e.Extra == -1) - { - nexpr = e; - break; - } // 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); - } - break; - case GMCode.Popz: - { - if (stack.Count == 0) nexpr = e; // else, ignore for switch - else - { - ILExpression call = stack.Peek() as ILExpression; - if (call != null && call.Code == GMCode.Call) - { - nexpr = call; - stack.Pop(); - } - else nexpr = e; // else, ignore for switch - } - } - break; - case GMCode.Bf: - case GMCode.Bt: - - if (stack.Count > 0 && e.Arguments.Count != 1) - { - Debug.Assert(stack.Count == 1); - e.Arguments[0] = NodeToExpresion(stack.Pop()); - } - nexpr = e; - break; - case GMCode.B: - case GMCode.Exit: - if (stack.Count > 0) - { - // we should only have ONE item left on the stack per block, and thats in wierd tertory shorts - Debug.Assert(stack.Count == 1); - list.Add(new ILExpression(GMCode.Push, null, NodeToExpresion(stack.Pop()))); - } - - nexpr = e; - break; // end of block, process at bottom - case GMCode.Ret: - throw new Exception("first return I have EVER seen"); - // try to resolve, if not ignore as its handled latter - - case GMCode.Dup: - if (stack.Count == 0) possableCase = true; - if (possableCase) - { - nexpr = e; - break; // break this and handle outside - } - // ok now we get into the meat of the issue, - // be sure we run switch detection BEFORE this function, otherwise, you will have a bad time:P - if ((int)e.Operand == 0) stack.Push(stack.Peek()); // simple case - 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 - Dup1Seen = true; // hack for now - foreach (var n in stack.ToArray()) stack.Push(n); // copy the entire stack - } - break; - default: // ok we handle an expression - if (e.Code.isExpression()) - { - for (int j = 0; j < e.Code.GetPopDelta(); j++) - e.Arguments.Add(NodeToExpresion(stack.Pop())); - e.Arguments.Reverse(); // till I fix it latter, sigh - stack.Push(e); // push expressions back - } - else nexpr = e; // fall though - break; - } - if (nexpr != null) list.Add(nexpr); - } - // this is going - // now the trick, if we still have stuff on the stack, put it back on the list - - CheckList(list); - if (list.Count == 0) return false; - else - { - head.Body = list; // replace the list - return true; - } } } } diff --git a/betteribttest/Dissasembler/GotoRemoval.cs b/betteribttest/Dissasembler/GotoRemoval.cs index 7f8e025..5048009 100644 --- a/betteribttest/Dissasembler/GotoRemoval.cs +++ b/betteribttest/Dissasembler/GotoRemoval.cs @@ -48,11 +48,11 @@ public void RemoveGotos(ILBlock method) public static void RemoveRedundantCode(ILBlock method) { - // Remove dead lables and nops + // Remove dead lables and nops and any popzs left HashSet liveLabels = new HashSet(method.GetSelfAndChildrenRecursive(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())); foreach (ILBlock block in method.GetSelfAndChildrenRecursive()) { - block.Body = block.Body.Where(n => !n.Match(GMCode.BadOp) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList(); + block.Body = block.Body.Where(n => !n.Match(GMCode.BadOp) && !n.Match(GMCode.Popz) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList(); } // Remove redundant continue @@ -101,7 +101,7 @@ public static void RemoveRedundantCode(ILBlock method) } } - + // Remove redundant return at the end of method if (method.Body.Count > 0 && (method.Body.Last().Match(GMCode.Ret)|| method.Body.Last().Match(GMCode.Exit) )&& ((ILExpression)method.Body.Last()).Arguments.Count == 0) { diff --git a/betteribttest/Dissasembler/LoopAndConditions.cs b/betteribttest/Dissasembler/LoopAndConditions.cs index c64ac79..021114b 100644 --- a/betteribttest/Dissasembler/LoopAndConditions.cs +++ b/betteribttest/Dissasembler/LoopAndConditions.cs @@ -159,7 +159,8 @@ List FindLoops(HashSet scope, ControlFlowNode entryPoin ILLabel trueLabel; ILLabel falseLabel; // It has to be just brtrue - any preceding code would introduce goto - if (basicBlock.MatchSingleAndBr(GMCode.Bf, out falseLabel, out condExpr, out trueLabel) || + if (basicBlock.MatchSingleAndBr(GMCode.Bf, out falseLabel, out condExpr, out trueLabel) || + // basicBlock.MatchSingleAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel) || basicBlock.MatchSingleAndBr(GMCode.Pushenv, out falseLabel, out condExpr, out trueLabel)) // built it the same way { bool ispushEnv = (basicBlock.Body.ElementAt(basicBlock.Body.Count - 2) as ILExpression).Code == GMCode.Pushenv; diff --git a/betteribttest/Dissasembler/Optimize.cs b/betteribttest/Dissasembler/Optimize.cs index 01eb743..da80b18 100644 --- a/betteribttest/Dissasembler/Optimize.cs +++ b/betteribttest/Dissasembler/Optimize.cs @@ -192,6 +192,7 @@ public static void RemoveRedundantCode(ILBlock method) else if (body[i].Match(GMCode.BadOp)) { // Ignore nop + } else { ILLabel label = body[i] as ILLabel; diff --git a/betteribttest/Dissasembler/PaternMatching.cs b/betteribttest/Dissasembler/PaternMatching.cs index 9a3ee4c..29ff479 100644 --- a/betteribttest/Dissasembler/PaternMatching.cs +++ b/betteribttest/Dissasembler/PaternMatching.cs @@ -76,8 +76,11 @@ public static bool Match(this ILNode node, GMCode code, out T operand) ILExpression expr = node as ILExpression; if (expr != null && expr.Code == code && expr.Arguments.Count == 0) { - operand = (T)expr.Operand; - return true; + if(expr.Operand is T) + { + operand = (T)expr.Operand; + return true; + } } operand = default(T); return false; diff --git a/betteribttest/FlowAnalysis/StackAnalysis.cs b/betteribttest/FlowAnalysis/StackAnalysis.cs index 1a6b9c3..c68dd04 100644 --- a/betteribttest/FlowAnalysis/StackAnalysis.cs +++ b/betteribttest/FlowAnalysis/StackAnalysis.cs @@ -377,15 +377,14 @@ public ILBlock Build(SortedList code, bool optimize, GMContext ILBlock method = new ILBlock(); method.Body = ast; - method.DebugSave("raw_body.txt"); + if (context.Debug) method.DebugSave("raw_body.txt"); betteribttest.Dissasembler.Optimize.RemoveRedundantCode(method); foreach(var block in method.GetSelfAndChildrenRecursive()) Optimize.SplitToBasicBlocks(block); -#if DEBUG - // DebugBasicBlocks(method); - method.DebugSave("basic_blocks.txt"); + if(context.Debug) method.DebugSave("basic_blocks.txt"); + new BuildFullAst(method, context).ProcessAllExpressions(method); - method.DebugSave("basic_blocks2.txt"); + if(context.Debug) method.DebugSave("basic_blocks2.txt"); foreach (ILBlock block in method.GetSelfAndChildrenRecursive()) { bool modified; @@ -401,52 +400,29 @@ public ILBlock Build(SortedList code, bool optimize, GMContext modified |= block.RunOptimization(Optimize.SimplifyLogicNot); } while (modified); } - method.DebugSave("basic_blocks3.txt"); - -#else - foreach (ILBlock block in method.GetSelfAndChildrenRecursive()) - { - bool modified; - do - { - modified = false; - - // modified |= block.RunOptimization(new SimpleControlFlow(method, context).SwitchDetection); - modified |= block.RunOptimization(ProcessExpressions); - modified |= block.RunOptimization(new SimpleControlFlow(method, context).PushEnviromentFix); - modified |= block.RunOptimization(new SimpleControlFlow(method, context).SimplifyShortCircuit); - modified |= block.RunOptimization(new SimpleControlFlow(method, context).SimplifyTernaryOperator); - - - modified |= block.RunOptimization(new SimpleControlFlow(method, context).JoinBasicBlocks); - modified |= block.RunOptimization(Optimize.SimplifyLogicNot); - } while (modified); - } -#endif - method.DebugSave("before_loop.txt"); + if (context.Debug) method.DebugSave("before_loop.txt"); foreach (ILBlock block in method.GetSelfAndChildrenRecursive()) { new LoopsAndConditions().FindLoops(block); } - method.DebugSave("before_conditions.txt"); + if (context.Debug) method.DebugSave("before_conditions.txt"); foreach (ILBlock block in method.GetSelfAndChildrenRecursive()) { new LoopsAndConditions().FindConditions(block); } FlattenBasicBlocks(method); - method.DebugSave("before_gotos.txt"); + if (context.Debug) method.DebugSave("before_gotos.txt"); Optimize.RemoveRedundantCode(method); new GotoRemoval().RemoveGotos(method); Optimize.RemoveRedundantCode(method); - // Debug.Assert(context.CurrentScript != "gml_Script_scr_phonename"); - new GotoRemoval().RemoveGotos(method); - //List body = StackAnalysis(method); - GotoRemoval.RemoveRedundantCode(method); - // We don't have a fancy + new GotoRemoval().RemoveGotos(method); + GotoRemoval.RemoveRedundantCode(method); + new GotoRemoval().RemoveGotos(method); + if (context.Debug) method.DebugSave("final.cpp"); return method; } diff --git a/betteribttest/GMContext.cs b/betteribttest/GMContext.cs index c1a5aa5..75a4a94 100644 --- a/betteribttest/GMContext.cs +++ b/betteribttest/GMContext.cs @@ -13,6 +13,7 @@ public class GMContext public List InstanceList; public List scriptList; public string CurrentScript = null; + public bool Debug = false; public string LookupString(int index, bool escape = false) { index &= 0x1FFFFF; diff --git a/betteribttest/Program.cs b/betteribttest/Program.cs index 69ab248..4dec87d 100644 --- a/betteribttest/Program.cs +++ b/betteribttest/Program.cs @@ -282,9 +282,10 @@ static void Main(string[] args) InstanceList = cr.objList.Select(x => x.Name).ToList(); scriptList = cr.scriptIndex.Select(x => x.script_name).ToList(); FunctionReplacement(); - GMContext context = new GMContext() { cr = cr, InstanceList = InstanceList, scriptList = scriptList }; + GMContext context = new GMContext() { cr = cr, InstanceList = InstanceList, scriptList = scriptList, Debug = false }; bool doAsm = false; bool all = false; + string toSearch = null; int pos = 1; while(pos < args.Length) @@ -296,6 +297,10 @@ static void Main(string[] args) toSearch = args.ElementAtOrDefault(pos); pos++; break; + case "-debug": + pos++; + context.Debug = true; + break; case "-all": all = true; pos++;