Skip to content

Commit

Permalink
Annnd DONE. I fixed default caes and put in a few clean ups. I still …
Browse files Browse the repository at this point in the history
…ahve this annoying bug where, for some reason, I get these extra goto's/labels to the default case and break of switches. I will live with it for now
  • Loading branch information
WarlockD committed Apr 21, 2016
1 parent 368eb5d commit a4ca2a3
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 292 deletions.
42 changes: 22 additions & 20 deletions betteribttest/ChunkReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -892,24 +892,38 @@ public IEnumerable<CodeData> GetCodeStreams()
{
foreach (GMK_Code c in codeList)
{
System.Diagnostics.Debug.WriteLine("Processing script {0}", c.Name);
ChunkStream ms = getReturnStream();
yield return new CodeData() { ScriptName = c.Name, stream = new BinaryReader(new OffsetStream(ms.BaseStream, c.startPosition, c.size)) };
}
}
public IEnumerable<CodeData> GetObjectCode(ref string objectName)
public IEnumerable<CodeData> GetCodeStreams(string search)
{
objectName = objectName.ToLower();
if (objectName.IndexOf("obj_") != 0) objectName = "obj_" + objectName;
var lookup = this.nameMap[objectName] as GMK_Object;
var list = GetCodeStreams(lookup.Name).ToList();
return list;
foreach (GMK_Code c in codeList.Where(x => x.Name.Contains(search)))
{
ChunkStream ms = getReturnStream();
yield return new CodeData() { ScriptName = c.Name, stream = new BinaryReader(new OffsetStream(ms.BaseStream, c.startPosition, c.size)) };
}
}
// silly wrapper
public IEnumerable<CodeData> GetAllScripts()
{
return GetCodeStreams("gml_Script");
}
public class ObjectCodeReturn
{
public List<CodeData> Streams;
public string ObjectName;
}
public IEnumerable<CodeData> GetObjectCode(ref string objectName)
{
objectName = objectName.ToLower();
if (objectName.IndexOf("obj_") != 0) objectName = "obj_" + objectName;
GMK_Data lookup;
if (!nameMap.TryGetValue(objectName, out lookup)) return new List<CodeData>();
//GMK_Object obj = lookup as GMK_Object;
return GetCodeStreams(lookup.Name).ToList();
}

public IEnumerable<ObjectCodeReturn> GetAllObjectCode()
{
foreach(GMK_Object o in nameMap.Values.OfType<GMK_Object>())
Expand All @@ -921,19 +935,7 @@ public IEnumerable<ObjectCodeReturn> GetAllObjectCode()
yield return ret;
}
}
public IEnumerable<CodeData> GetCodeStreams(string code_name)
{
foreach (GMK_Code c in codeList)
{
if (c.Name.ToLower().IndexOf(code_name) != -1)
{
System.Diagnostics.Debug.WriteLine("Processing script {0}", c.Name);
//System.Diagnostics.Debug.Assert("gml_Object_obj_finalfroggit_Alarm_6" != c.Name);
ChunkStream ms = getReturnStream();
yield return new CodeData() { ScriptName= c.Name, stream= new BinaryReader(new OffsetStream(ms.BaseStream, c.startPosition, c.size)) };
}
}
}

void doSCPT(int chunkStart, int chunkLimit)
{
ChunkEntries entries = new ChunkEntries(r, chunkStart, chunkLimit);
Expand Down
81 changes: 65 additions & 16 deletions betteribttest/Dissasembler/BuildFullAst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class BuildFullAst
{
Dictionary<ILLabel, int> labelGlobalRefCount = new Dictionary<ILLabel, int>();
Dictionary<ILLabel, ILBasicBlock> labelToBasicBlock = new Dictionary<ILLabel, ILBasicBlock>();

GMContext context;
ILBlock method;
// TypeSystem typeSystem;
Expand All @@ -33,6 +34,18 @@ public BuildFullAst(ILBlock method, GMContext context)
}
}
}
Dictionary<ILLabel, ILBasicBlock> labelToNextBlock;
void BuildNextBlockData()
{
labelToNextBlock = new Dictionary<ILLabel, ILBasicBlock>();
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;
ILLabel label = (bb.Body.First() as ILLabel);
labelToNextBlock[label] = next;
}
}
void ProcessVar(ILVariable v, Stack<ILNode> stack)
{
if (v.isResolved) return; // nothing to do
Expand Down Expand Up @@ -155,7 +168,8 @@ Status ProcessExpression(List<ILNode> list, ILBasicBlock head, int pos, Stack<IL
{
if (stack.Count == 0)
{
Debug.Assert(false);
list.Add(e);
// Debug.Assert(false);
return Status.ChangedAdded;
}
else
Expand All @@ -172,27 +186,27 @@ Status ProcessExpression(List<ILNode> list, ILBasicBlock head, int pos, Stack<IL
}
case GMCode.Bf:
case GMCode.Bt:
case GMCode.Ret:
if (stack.Count > 0)
{
Debug.Assert(stack.Count == 1);
// 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.Ret:
case GMCode.B:
case GMCode.Exit:
if (stack.Count > 0)
{
foreach (var n in stack) list.Add(new ILExpression(GMCode.Push, null, NodeToExpresion(n)));

// we should only have ONE item left on the stack per block, and thats in wierd tertory shorts
Debug.Assert(stack.Count == 1);
// be sure to push eveything on the block first do be handled ladder
}
list.Add(e);
return Status.ChangedAdded;
Expand All @@ -215,7 +229,13 @@ Status ProcessExpression(List<ILNode> list, ILBasicBlock head, int pos, Stack<IL
if (e.Code.isExpression())
{
for (int j = 0; j < e.Code.GetPopDelta(); j++)
e.Arguments.Add(NodeToExpresion(stack.Pop()));
{
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;
Expand Down Expand Up @@ -257,6 +277,7 @@ void ProcessExpressions(List<ILNode> body, ILBasicBlock head, int pos)
head.MatchAt(i + 3, GMCode.Bt))
{
// 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);
Expand All @@ -275,22 +296,50 @@ void ProcessExpressions(List<ILNode> body, ILBasicBlock head, int pos)
body.Remove(current);
current = labelToBasicBlock[nextCase];
}
body.Insert(0, head);
switchExpression.Operand = caseLabels.ToArray();
body.Insert(pos, head);

var lastBlock = current;


ILLabel fallLabel;
if (!current.MatchSingle(GMCode.B, out fallLabel)) throw new Exception("fix");
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));
current = labelToBasicBlock[fallLabel];
if (!current.MatchAt(1, GMCode.Popz)) throw new Exception("fix");
current.Body.RemoveAt(1); // remove the pop z


break; // we are done with this block
}
else
{
Status s = ProcessExpression(list,head, i, stack);
Status s = ProcessExpression(list, head, i, stack);

}
}

Expand Down
18 changes: 15 additions & 3 deletions betteribttest/Dissasembler/GMAstTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,8 @@ bool CheckParm(int index)
}
void WriteOperand(ITextOutput output,bool escapeString=true)
{
if (Operand is ILLabel) output.Write((Operand as ILLabel).Name);
if (Operand == null) output.Write("%NULL_OPERAND%");
else if (Operand is ILLabel) output.Write((Operand as ILLabel).Name);
else if (escapeString)
{
if (Operand is string)
Expand Down Expand Up @@ -591,8 +592,15 @@ public override void WriteTo(ITextOutput output)

break;
case GMCode.Pop:
output.Write("Pop: ");
WriteOperand(output, false);// generic, string name
if(Operand == null) output.Write(POPDefaultString);
else {
output.Write("Pop(");
WriteOperand(output, false);// generic, string name
output.Write(" = ");
output.Write(POPDefaultString);
output.Write(")");
}

break;
case GMCode.Assign:
WriteArgumentOrPop(output, 0, false);
Expand Down Expand Up @@ -668,6 +676,10 @@ public override void WriteTo(ITextOutput output)
case GMCode.LoopContinue:
output.Write("continue");
break;
case GMCode.DefaultCase:
output.Write("default: goto ");
WriteOperand(output);
break;
case GMCode.Case:
output.Write("case ");
WriteArgumentOrPop(output, 0);
Expand Down
4 changes: 3 additions & 1 deletion betteribttest/Dissasembler/GotoRemoval.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static void RemoveRedundantCode(ILBlock method)
{
// Remove dead lables and nops
HashSet<ILLabel> liveLabels = new HashSet<ILLabel>(method.GetSelfAndChildrenRecursive<ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets()));
foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>())
foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>())
{
block.Body = block.Body.Where(n => !n.Match(GMCode.BadOp) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList();
}
Expand Down Expand Up @@ -91,13 +91,15 @@ public static void RemoveRedundantCode(ILBlock method)
}
}
}
// fix case block

var defaultCase = ilSwitch.CaseBlocks.SingleOrDefault(cb => cb.Values == null);
// If there is no default block, remove empty case blocks
if (defaultCase == null || (defaultCase.Body.Count == 1 && defaultCase.Body.Single().Match(GMCode.LoopOrSwitchBreak)))
{
ilSwitch.CaseBlocks.RemoveAll(b => b.Body.Count == 1 && b.Body.Single().Match(GMCode.LoopOrSwitchBreak));
}

}

// Remove redundant return at the end of method
Expand Down
66 changes: 5 additions & 61 deletions betteribttest/Dissasembler/LoopAndConditions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,66 +132,7 @@ ControlFlowGraph BuildGraph(IList<ILNode> nodes, ILLabel entryLabel)
return new ControlFlowGraph(cfNodes.ToArray());
}


List<ILNode> FindWiths(HashSet<ControlFlowNode> scope, ControlFlowNode entryPoint, bool excludeEntryPoint)
{
List<ILNode> result = new List<ILNode>();

// Do not modify entry data
scope = new HashSet<ControlFlowNode>(scope);
Queue<ControlFlowNode> agenda = new Queue<ControlFlowNode>();
agenda.Enqueue(entryPoint);
while (agenda.Count > 0)
{
ControlFlowNode node = agenda.Dequeue();
// Find a block that represents a simple condition
if (scope.Contains(node))
{
ILBasicBlock head = (ILBasicBlock)node.UserData;
ILLabel pushlabel;
ILLabel nextLabel;
if (head.MatchLastAndBr(GMCode.Popenv, out pushlabel, out nextLabel) &&
pushlabel == nextLabel // This is not a break
)
{
scope.RemoveOrThrow(node);
// alright we do this like we did the simple
ILExpression popExpression = head.Body[head.Body.Count - 2] as ILExpression;

Stack<ILNode> pushExpresions = new Stack<ILNode>(); // have to reverse the order
int i;
ILExpression e = null;
for (i = head.Body.Count - 3; i >= 0; i--)
{
ILNode n = head.Body[i];
Debug.Assert(!(n is ILLabel)); // We need to handle a break then
e = n as ILExpression;
if (e != null && e.Code == GMCode.Pushenv) break;
pushExpresions.Push(n);
}
ILWithStatement stmt = new ILWithStatement();
stmt.Enviroment = e.Arguments[0];
foreach (var f in pushExpresions) { stmt.Body.Body.Add(f); head.Body.Remove(f); }
head.Body.Remove(popExpression);
head.Body[i] = stmt;
e.Code = GMCode.SimplePushenv;
}
}
// 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 scope)
{
result.Add((ILNode)node.UserData);
}

return result;
}

List<ILNode> FindLoops(HashSet<ControlFlowNode> scope, ControlFlowNode entryPoint, bool excludeEntryPoint)
{
List<ILNode> result = new List<ILNode>();
Expand Down Expand Up @@ -417,7 +358,10 @@ List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entr
});
}
}
caseBlock.Values.Add(cases[i].Arguments[0]);
if (cases[i].Code != GMCode.DefaultCase)
caseBlock.Values.Add(cases[i].Arguments[0]);
else
caseBlock.Values.Add(new ILExpression(GMCode.DefaultCase, null));
}

// Heuristis to determine if we want to use fallthough as default case
Expand Down
5 changes: 0 additions & 5 deletions betteribttest/Dissasembler/Optimize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@ public static void RemoveRedundantCode(ILBlock method)
for (int i = 0; i < body.Count; i++)
{
ILLabel target;
ILExpression popExpr;
if (body[i].Match(GMCode.B, out target) && i + 1 < body.Count && body[i + 1] == target)
{
// Ignore the branch
Expand All @@ -194,10 +193,6 @@ public static void RemoveRedundantCode(ILBlock method)
{
// Ignore nop
}
else if (body[i].Match(GMCode.Pop, out popExpr))
{
foreach (var t in popExpr.Arguments) if (t.Code == GMCode.Pop) throw new Exception("We should have NO pop expresions insde of a pop expression");
}
else {
ILLabel label = body[i] as ILLabel;
if (label != null)
Expand Down
Loading

0 comments on commit a4ca2a3

Please sign in to comment.