Implement basic control block support
This commit is contained in:
Родитель
1205ecb5cb
Коммит
ff92ec08d7
|
@ -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());
|
||||||
|
|
Загрузка…
Ссылка в новой задаче