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; @@ -21,6 +21,7 @@ using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.Disassembler
{
@ -123,5 +124,31 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -123,5 +124,31 @@ namespace ICSharpCode.Decompiler.Disassembler
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 @@ -131,7 +131,8 @@ namespace ICSharpCode.Decompiler.Disassembler
if (DetectControlStructure && blob.Length > 0)
{
blob.Reset();
HashSet<int> branchTargets = GetBranchTargets(blob);
BitSet branchTargets = new(blob.Length);
ILParser.SetBranchTargets(ref blob, branchTargets);
blob.Reset();
WriteStructureBody(new ILStructure(module, handle, genericContext, body), branchTargets, ref blob, methodDefinition.RelativeVirtualAddress + headerSize);
}
@ -212,28 +213,6 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -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)
{
switch (s.Type)
@ -286,7 +265,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -286,7 +265,7 @@ namespace ICSharpCode.Decompiler.Disassembler
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 prevInstructionWasBranch = false;
@ -304,7 +283,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -304,7 +283,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
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
}

2
ICSharpCode.Decompiler/IL/BlockBuilder.cs

@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.IL @@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.IL
Block currentBlock;
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();
mainContainer.SetILRange(new Interval(0, body.GetCodeSize()));

98
ICSharpCode.Decompiler/IL/ILReader.cs

@ -80,7 +80,7 @@ namespace ICSharpCode.Decompiler.IL @@ -80,7 +80,7 @@ namespace ICSharpCode.Decompiler.IL
ImmutableStack<ILVariable> currentStack;
ILVariable[] parameterVariables;
ILVariable[] localVariables;
BitArray isBranchTarget;
BitSet isBranchTarget;
BlockContainer mainContainer;
List<ILInstruction> instructionBuilder;
int currentInstructionStart;
@ -125,7 +125,7 @@ namespace ICSharpCode.Decompiler.IL @@ -125,7 +125,7 @@ namespace ICSharpCode.Decompiler.IL
}
this.mainContainer = new BlockContainer(expectedResultType: methodReturnStackType);
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.variableByExceptionHandler = new Dictionary<ExceptionRegion, ILVariable>();
}
@ -390,44 +390,10 @@ namespace ICSharpCode.Decompiler.IL @@ -390,44 +390,10 @@ namespace ICSharpCode.Decompiler.IL
void ReadInstructions(CancellationToken cancellationToken)
{
// Fill isBranchTarget and branchStackDict based on exception handlers
foreach (var eh in body.ExceptionRegions)
{
ImmutableStack<ILVariable> ehStack = null;
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();
ILParser.SetBranchTargets(ref reader, isBranchTarget);
reader.Reset();
PrepareBranchTargetsAndStacksForExceptionHandlers();
reader.Reset();
while (reader.RemainingBytes > 0)
@ -476,13 +442,55 @@ namespace ICSharpCode.Decompiler.IL @@ -476,13 +442,55 @@ namespace ICSharpCode.Decompiler.IL
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)
{
if (instruction.OpCode == OpCode.Nop ||
(this.instructionBuilder.Count > 0 &&
this.instructionBuilder.Last().OpCode == OpCode.Call ||
this.instructionBuilder.Last().OpCode == OpCode.CallIndirect ||
this.instructionBuilder.Last().OpCode == OpCode.CallVirt))
(instructionBuilder.Count > 0
&& instructionBuilder.Last().OpCode is OpCode.Call
or OpCode.CallIndirect
or OpCode.CallVirt))
{
return true;
@ -1787,7 +1795,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1787,7 +1795,7 @@ namespace ICSharpCode.Decompiler.IL
void MarkBranchTarget(int targetILOffset)
{
isBranchTarget[targetILOffset] = true;
Debug.Assert(isBranchTarget[targetILOffset]);
StoreStackForOffset(targetILOffset, ref currentStack);
}

Loading…
Cancel
Save