Implement basic control block support

This commit is contained in:
HoLLy 2019-11-23 17:08:33 +01:00
Родитель 1205ecb5cb
Коммит ff92ec08d7
3 изменённых файлов: 42 добавлений и 13 удалений

Просмотреть файл

@ -5,6 +5,7 @@ using System.IO;
using System.Linq; using System.Linq;
using Rivers; using Rivers;
using Rivers.Analysis; using Rivers.Analysis;
using Rivers.Serialization.Dot;
using WasmLib.Decompilation.Intermediate; using WasmLib.Decompilation.Intermediate;
using WasmLib.Decompilation.Intermediate.Graph; using WasmLib.Decompilation.Intermediate.Graph;
using WasmLib.Decompilation.SourceCode; using WasmLib.Decompilation.SourceCode;
@ -49,17 +50,18 @@ namespace WasmLib.Decompilation
int instructionNum = 0; int instructionNum = 0;
foreach (IntermediateInstruction instruction in instructions) { foreach (IntermediateInstruction instruction in instructions) {
if (instruction.HasBlock) { InstructionNode node = !instruction.HasBlock
throw new NotImplementedException(); ? new InstructionNode(instruction, instructionNum++)
} : instruction.Block2 == null
? new InstructionNode(instruction, instructionNum++, CreateGraph(instruction.Block1!.Instructions))
: new InstructionNode(instruction, instructionNum++, CreateGraph(instruction.Block1!.Instructions), CreateGraph(instruction.Block2.Instructions));
InstructionNode node = new InstructionNode(instruction, instructionNum++);
graph.Nodes.Add(node); graph.Nodes.Add(node);
Debug.Assert(instruction.PushCount <= 1, "Instruction pushed multiple variables to stack, which shouldn't happen."); Debug.Assert(instruction.PushCount <= 1, "Instruction pushed multiple variables to stack, which shouldn't happen.");
for (int i = 0; i < instruction.PopCount; i++) { for (int i = 0; i < instruction.PopCount; i++) {
(InstructionNode sourceInstruction, ValueKind type) = stack.Pop(); (InstructionNode sourceInstruction, ValueKind type) = stack.Pop();
Debug.Assert(type == instruction.PopTypes[i]); Debug.Assert(type == instruction.PopTypes[i] || type == ValueKind.Any || instruction.PopTypes[i] == ValueKind.Any);
sourceInstruction.OutgoingEdges.Add(new StackVariableEdge(sourceInstruction, node, type)); sourceInstruction.OutgoingEdges.Add(new StackVariableEdge(sourceInstruction, node, type));
} }
@ -79,13 +81,16 @@ namespace WasmLib.Decompilation
// BUG: see Washi1337/Rivers#6 // BUG: see Washi1337/Rivers#6
// Debug.Assert(!graph.IsCyclic(), "Got cyclic dependency in function!"); // Debug.Assert(!graph.IsCyclic(), "Got cyclic dependency in function!");
if (!graph.IsConnected()) { if (!graph.IsConnected()) {
#if DEBUG
using (StreamWriter sw = new StreamWriter(File.OpenWrite("temp_unconnected.dot"))) new DotWriter(sw).Write(graph);
#endif
throw new NotImplementedException(); throw new NotImplementedException();
} }
return graph; return graph;
} }
private static void OutputAsCode(Graph graph, TextWriter output) private static void OutputAsCode(Graph graph, TextWriter output, int tabCount = 1)
{ {
var varCounts = new Dictionary<ValueKind, int> { var varCounts = new Dictionary<ValueKind, int> {
{ValueKind.I32, 0}, {ValueKind.I32, 0},
@ -120,17 +125,32 @@ namespace WasmLib.Decompilation
} }
} }
statements[currentNode.Index] = new GenericExpression(currentNode.Instruction, parameters); statements[currentNode.Index] = new GenericExpression(currentNode.Instruction, parameters, currentNode.Block1, currentNode.Block2);
} }
else { else {
statements[currentNode.Index] = new GenericExpression(currentNode.Instruction); statements[currentNode.Index] = new GenericExpression(currentNode.Instruction, null, currentNode.Block1, currentNode.Block2);
} }
} }
foreach (IExpression expression in statements.Values) { foreach (IExpression expression in statements.Values) {
// TODO: support comments // TODO: support comments
output.WriteLine(new string('\t', 1) + expression.GetStringRepresentation()); if (expression is GenericExpression ge && ge.Block1 != null) {
output.WriteLine(new string('\t', tabCount) + expression.GetStringRepresentation() + " {");
OutputAsCode(ge.Block1, output, tabCount + 1);
if (ge.Block2 == null) {
output.WriteLine(new string('\t', tabCount) + "}");
}
else {
output.WriteLine(new string('\t', tabCount) + "} else {");
OutputAsCode(ge.Block2, output, tabCount + 1);
output.WriteLine(new string('\t', tabCount) + "}");
}
}
else {
output.WriteLine(new string('\t', tabCount) + expression.GetStringRepresentation());
}
} }
} }
} }

Просмотреть файл

@ -15,11 +15,15 @@ namespace WasmLib.Decompilation.Intermediate.Graph
public IEnumerable<ImpurityDependencyEdge> IncomingImpurityEdges => IncomingEdges.OfType<ImpurityDependencyEdge>(); public IEnumerable<ImpurityDependencyEdge> IncomingImpurityEdges => IncomingEdges.OfType<ImpurityDependencyEdge>();
public IEnumerable<StackVariableEdge> OutgoingVariableEdges => OutgoingEdges.OfType<StackVariableEdge>(); public IEnumerable<StackVariableEdge> OutgoingVariableEdges => OutgoingEdges.OfType<StackVariableEdge>();
public IEnumerable<StackVariableEdge> IncomingVariableEdges => IncomingEdges.OfType<StackVariableEdge>(); public IEnumerable<StackVariableEdge> IncomingVariableEdges => IncomingEdges.OfType<StackVariableEdge>();
public Rivers.Graph? Block1 { get; }
public Rivers.Graph? Block2 { get; }
public InstructionNode(IntermediateInstruction instruction, int idx) : base($"_{idx:X4}") public InstructionNode(IntermediateInstruction instruction, int idx, Rivers.Graph? block1 = null, Rivers.Graph? block2 = null) : base($"_{idx:X4}")
{ {
Instruction = instruction; Instruction = instruction;
Index = idx; Index = idx;
Block1 = block1;
Block2 = block2;
AddUserData(); AddUserData();
} }

Просмотреть файл

@ -1,4 +1,5 @@
using System.Linq; using System.Linq;
using Rivers;
using WasmLib.Decompilation.Intermediate; using WasmLib.Decompilation.Intermediate;
using WasmLib.Utils; using WasmLib.Utils;
@ -8,11 +9,15 @@ namespace WasmLib.Decompilation.SourceCode
{ {
public IntermediateInstruction BaseInstruction { get; } public IntermediateInstruction BaseInstruction { get; }
public IExpression[]? Parameters { get; } public IExpression[]? Parameters { get; }
public Graph? Block1 { get; }
public Graph? Block2 { get; }
public GenericExpression(IntermediateInstruction baseInstruction, IExpression[]? parameters = null) public GenericExpression(IntermediateInstruction baseInstruction, IExpression[]? parameters = null, Graph? block1 = null, Graph? block2 = null)
{ {
BaseInstruction = baseInstruction; BaseInstruction = baseInstruction;
Parameters = parameters; Parameters = parameters;
Block1 = block1;
Block2 = block2;
} }
public string GetStringRepresentation() => BaseInstruction.OperationStringFormat.SafeFormat(Parameters?.Select(x => x.GetStringRepresentation()).ToArray()); public string GetStringRepresentation() => BaseInstruction.OperationStringFormat.SafeFormat(Parameters?.Select(x => x.GetStringRepresentation()).ToArray());