From af56bb10d076c716691263787b8b1a545f079803 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 17 Jul 2022 09:56:23 +0200 Subject: [PATCH] Determine isBranchTarget in a separate pass. We will need it for an optimization to ILReader in a future commit. --- .../Disassembler/ILParser.cs | 27 +++++ .../Disassembler/MethodBodyDisassembler.cs | 29 +----- ICSharpCode.Decompiler/IL/BlockBuilder.cs | 2 +- ICSharpCode.Decompiler/IL/ILReader.cs | 98 ++++++++++--------- 4 files changed, 85 insertions(+), 71 deletions(-) diff --git a/ICSharpCode.Decompiler/Disassembler/ILParser.cs b/ICSharpCode.Decompiler/Disassembler/ILParser.cs index 4b606c83f..3340c82a7 100644 --- a/ICSharpCode.Decompiler/Disassembler/ILParser.cs +++ b/ICSharpCode.Decompiler/Disassembler/ILParser.cs @@ -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 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); + } + } + } } } diff --git a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs index d297f77e3..bd03f69e6 100644 --- a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs @@ -131,7 +131,8 @@ namespace ICSharpCode.Decompiler.Disassembler if (DetectControlStructure && blob.Length > 0) { blob.Reset(); - HashSet 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 } } - HashSet GetBranchTargets(BlobReader blob) - { - HashSet branchTargets = new HashSet(); - 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 output.Indent(); } - void WriteStructureBody(ILStructure s, HashSet 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 } 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 } diff --git a/ICSharpCode.Decompiler/IL/BlockBuilder.cs b/ICSharpCode.Decompiler/IL/BlockBuilder.cs index ee02e0f8b..75a7613bf 100644 --- a/ICSharpCode.Decompiler/IL/BlockBuilder.cs +++ b/ICSharpCode.Decompiler/IL/BlockBuilder.cs @@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.IL Block currentBlock; readonly Stack containerStack = new Stack(); - public void CreateBlocks(BlockContainer mainContainer, List instructions, BitArray incomingBranches, CancellationToken cancellationToken) + public void CreateBlocks(BlockContainer mainContainer, List instructions, BitSet incomingBranches, CancellationToken cancellationToken) { CreateContainerStructure(); mainContainer.SetILRange(new Interval(0, body.GetCodeSize())); diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index b388da5b1..c81b70f5d 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -80,7 +80,7 @@ namespace ICSharpCode.Decompiler.IL ImmutableStack currentStack; ILVariable[] parameterVariables; ILVariable[] localVariables; - BitArray isBranchTarget; + BitSet isBranchTarget; BlockContainer mainContainer; List instructionBuilder; int currentInstructionStart; @@ -125,7 +125,7 @@ namespace ICSharpCode.Decompiler.IL } this.mainContainer = new BlockContainer(expectedResultType: methodReturnStackType); this.instructionBuilder = new List(); - this.isBranchTarget = new BitArray(reader.Length); + this.isBranchTarget = new BitSet(reader.Length); this.stackByOffset = new Dictionary>(); this.variableByExceptionHandler = new Dictionary(); } @@ -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 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.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 InsertStackAdjustments(); } + private void PrepareBranchTargetsAndStacksForExceptionHandlers() + { + // Fill isBranchTarget and branchStackDict based on exception handlers + foreach (var eh in body.ExceptionRegions) + { + ImmutableStack 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.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 void MarkBranchTarget(int targetILOffset) { - isBranchTarget[targetILOffset] = true; + Debug.Assert(isBranchTarget[targetILOffset]); StoreStackForOffset(targetILOffset, ref currentStack); }