Browse Source

Determine isBranchTarget in a separate pass. We will need it for an optimization to ILReader in a future commit.

pull/2766/head
Siegfried Pammer 3 years ago
parent
commit
af56bb10d0
  1. 27
      ICSharpCode.Decompiler/Disassembler/ILParser.cs
  2. 29
      ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  3. 2
      ICSharpCode.Decompiler/IL/BlockBuilder.cs
  4. 98
      ICSharpCode.Decompiler/IL/ILReader.cs

27
ICSharpCode.Decompiler/Disassembler/ILParser.cs

@ -21,6 +21,7 @@ using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata.Ecma335;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.Disassembler namespace ICSharpCode.Decompiler.Disassembler
{ {
@ -123,5 +124,31 @@ namespace ICSharpCode.Decompiler.Disassembler
return 1; return 1;
} }
} }
public static void SetBranchTargets(ref BlobReader blob, BitSet branchTargets)
{
while (blob.RemainingBytes > 0)
{
var opCode = DecodeOpCode(ref blob);
if (opCode == ILOpCode.Switch)
{
foreach (var target in DecodeSwitchTargets(ref blob))
{
if (target >= 0 && target < blob.Length)
branchTargets.Set(target);
}
}
else if (opCode.IsBranch())
{
int target = DecodeBranchTarget(ref blob, opCode);
if (target >= 0 && target < blob.Length)
branchTargets.Set(target);
}
else
{
SkipOperand(ref blob, opCode);
}
}
}
} }
} }

29
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -131,7 +131,8 @@ namespace ICSharpCode.Decompiler.Disassembler
if (DetectControlStructure && blob.Length > 0) if (DetectControlStructure && blob.Length > 0)
{ {
blob.Reset(); blob.Reset();
HashSet<int> branchTargets = GetBranchTargets(blob); BitSet branchTargets = new(blob.Length);
ILParser.SetBranchTargets(ref blob, branchTargets);
blob.Reset(); blob.Reset();
WriteStructureBody(new ILStructure(module, handle, genericContext, body), branchTargets, ref blob, methodDefinition.RelativeVirtualAddress + headerSize); WriteStructureBody(new ILStructure(module, handle, genericContext, body), branchTargets, ref blob, methodDefinition.RelativeVirtualAddress + headerSize);
} }
@ -212,28 +213,6 @@ namespace ICSharpCode.Decompiler.Disassembler
} }
} }
HashSet<int> GetBranchTargets(BlobReader blob)
{
HashSet<int> branchTargets = new HashSet<int>();
while (blob.RemainingBytes > 0)
{
var opCode = ILParser.DecodeOpCode(ref blob);
if (opCode == ILOpCode.Switch)
{
branchTargets.UnionWith(ILParser.DecodeSwitchTargets(ref blob));
}
else if (opCode.IsBranch())
{
branchTargets.Add(ILParser.DecodeBranchTarget(ref blob, opCode));
}
else
{
ILParser.SkipOperand(ref blob, opCode);
}
}
return branchTargets;
}
void WriteStructureHeader(ILStructure s) void WriteStructureHeader(ILStructure s)
{ {
switch (s.Type) switch (s.Type)
@ -286,7 +265,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Indent(); output.Indent();
} }
void WriteStructureBody(ILStructure s, HashSet<int> branchTargets, ref BlobReader body, int methodRva) void WriteStructureBody(ILStructure s, BitSet branchTargets, ref BlobReader body, int methodRva)
{ {
bool isFirstInstructionInStructure = true; bool isFirstInstructionInStructure = true;
bool prevInstructionWasBranch = false; bool prevInstructionWasBranch = false;
@ -304,7 +283,7 @@ namespace ICSharpCode.Decompiler.Disassembler
} }
else else
{ {
if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets[offset]))
{ {
output.WriteLine(); // put an empty line after branches, and in front of branch targets output.WriteLine(); // put an empty line after branches, and in front of branch targets
} }

2
ICSharpCode.Decompiler/IL/BlockBuilder.cs

@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.IL
Block currentBlock; Block currentBlock;
readonly Stack<BlockContainer> containerStack = new Stack<BlockContainer>(); readonly Stack<BlockContainer> containerStack = new Stack<BlockContainer>();
public void CreateBlocks(BlockContainer mainContainer, List<ILInstruction> instructions, BitArray incomingBranches, CancellationToken cancellationToken) public void CreateBlocks(BlockContainer mainContainer, List<ILInstruction> instructions, BitSet incomingBranches, CancellationToken cancellationToken)
{ {
CreateContainerStructure(); CreateContainerStructure();
mainContainer.SetILRange(new Interval(0, body.GetCodeSize())); mainContainer.SetILRange(new Interval(0, body.GetCodeSize()));

98
ICSharpCode.Decompiler/IL/ILReader.cs

@ -80,7 +80,7 @@ namespace ICSharpCode.Decompiler.IL
ImmutableStack<ILVariable> currentStack; ImmutableStack<ILVariable> currentStack;
ILVariable[] parameterVariables; ILVariable[] parameterVariables;
ILVariable[] localVariables; ILVariable[] localVariables;
BitArray isBranchTarget; BitSet isBranchTarget;
BlockContainer mainContainer; BlockContainer mainContainer;
List<ILInstruction> instructionBuilder; List<ILInstruction> instructionBuilder;
int currentInstructionStart; int currentInstructionStart;
@ -125,7 +125,7 @@ namespace ICSharpCode.Decompiler.IL
} }
this.mainContainer = new BlockContainer(expectedResultType: methodReturnStackType); this.mainContainer = new BlockContainer(expectedResultType: methodReturnStackType);
this.instructionBuilder = new List<ILInstruction>(); this.instructionBuilder = new List<ILInstruction>();
this.isBranchTarget = new BitArray(reader.Length); this.isBranchTarget = new BitSet(reader.Length);
this.stackByOffset = new Dictionary<int, ImmutableStack<ILVariable>>(); this.stackByOffset = new Dictionary<int, ImmutableStack<ILVariable>>();
this.variableByExceptionHandler = new Dictionary<ExceptionRegion, ILVariable>(); this.variableByExceptionHandler = new Dictionary<ExceptionRegion, ILVariable>();
} }
@ -390,44 +390,10 @@ namespace ICSharpCode.Decompiler.IL
void ReadInstructions(CancellationToken cancellationToken) void ReadInstructions(CancellationToken cancellationToken)
{ {
// Fill isBranchTarget and branchStackDict based on exception handlers reader.Reset();
foreach (var eh in body.ExceptionRegions) ILParser.SetBranchTargets(ref reader, isBranchTarget);
{ reader.Reset();
ImmutableStack<ILVariable> ehStack = null; PrepareBranchTargetsAndStacksForExceptionHandlers();
if (eh.Kind == ExceptionRegionKind.Catch)
{
var catchType = module.ResolveType(eh.CatchType, genericContext);
var v = new ILVariable(VariableKind.ExceptionStackSlot, catchType, eh.HandlerOffset) {
Name = "E_" + eh.HandlerOffset,
HasGeneratedName = true
};
variableByExceptionHandler.Add(eh, v);
ehStack = ImmutableStack.Create(v);
}
else if (eh.Kind == ExceptionRegionKind.Filter)
{
var v = new ILVariable(VariableKind.ExceptionStackSlot, compilation.FindType(KnownTypeCode.Object), eh.HandlerOffset) {
Name = "E_" + eh.HandlerOffset,
HasGeneratedName = true
};
variableByExceptionHandler.Add(eh, v);
ehStack = ImmutableStack.Create(v);
}
else
{
ehStack = ImmutableStack<ILVariable>.Empty;
}
if (eh.FilterOffset != -1)
{
isBranchTarget[eh.FilterOffset] = true;
StoreStackForOffset(eh.FilterOffset, ref ehStack);
}
if (eh.HandlerOffset != -1)
{
isBranchTarget[eh.HandlerOffset] = true;
StoreStackForOffset(eh.HandlerOffset, ref ehStack);
}
}
reader.Reset(); reader.Reset();
while (reader.RemainingBytes > 0) while (reader.RemainingBytes > 0)
@ -476,13 +442,55 @@ namespace ICSharpCode.Decompiler.IL
InsertStackAdjustments(); InsertStackAdjustments();
} }
private void PrepareBranchTargetsAndStacksForExceptionHandlers()
{
// Fill isBranchTarget and branchStackDict based on exception handlers
foreach (var eh in body.ExceptionRegions)
{
ImmutableStack<ILVariable> ehStack;
if (eh.Kind == ExceptionRegionKind.Catch)
{
var catchType = module.ResolveType(eh.CatchType, genericContext);
var v = new ILVariable(VariableKind.ExceptionStackSlot, catchType, eh.HandlerOffset) {
Name = "E_" + eh.HandlerOffset,
HasGeneratedName = true
};
variableByExceptionHandler.Add(eh, v);
ehStack = ImmutableStack.Create(v);
}
else if (eh.Kind == ExceptionRegionKind.Filter)
{
var v = new ILVariable(VariableKind.ExceptionStackSlot, compilation.FindType(KnownTypeCode.Object), eh.HandlerOffset) {
Name = "E_" + eh.HandlerOffset,
HasGeneratedName = true
};
variableByExceptionHandler.Add(eh, v);
ehStack = ImmutableStack.Create(v);
}
else
{
ehStack = ImmutableStack<ILVariable>.Empty;
}
if (eh.FilterOffset != -1)
{
isBranchTarget[eh.FilterOffset] = true;
StoreStackForOffset(eh.FilterOffset, ref ehStack);
}
if (eh.HandlerOffset != -1)
{
isBranchTarget[eh.HandlerOffset] = true;
StoreStackForOffset(eh.HandlerOffset, ref ehStack);
}
}
}
private bool IsSequencePointInstruction(ILInstruction instruction) private bool IsSequencePointInstruction(ILInstruction instruction)
{ {
if (instruction.OpCode == OpCode.Nop || if (instruction.OpCode == OpCode.Nop ||
(this.instructionBuilder.Count > 0 && (instructionBuilder.Count > 0
this.instructionBuilder.Last().OpCode == OpCode.Call || && instructionBuilder.Last().OpCode is OpCode.Call
this.instructionBuilder.Last().OpCode == OpCode.CallIndirect || or OpCode.CallIndirect
this.instructionBuilder.Last().OpCode == OpCode.CallVirt)) or OpCode.CallVirt))
{ {
return true; return true;
@ -1787,7 +1795,7 @@ namespace ICSharpCode.Decompiler.IL
void MarkBranchTarget(int targetILOffset) void MarkBranchTarget(int targetILOffset)
{ {
isBranchTarget[targetILOffset] = true; Debug.Assert(isBranchTarget[targetILOffset]);
StoreStackForOffset(targetILOffset, ref currentStack); StoreStackForOffset(targetILOffset, ref currentStack);
} }

Loading…
Cancel
Save