diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs b/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs index 474e3031d..fc71d55d0 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs @@ -93,6 +93,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow } PickBetterBlockExit(block, ifInst); OrderIfBlocks(ifInst); + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; } /// @@ -150,6 +151,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow // The targetBlock was already processed, and is ready to embed var targetBlock = ((Branch)exitInst).TargetBlock; block.Instructions.RemoveAt(block.Instructions.Count - 1); + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; block.Instructions.AddRange(targetBlock.Instructions); targetBlock.Remove(); diff --git a/ICSharpCode.Decompiler/IL/Instructions/Block.cs b/ICSharpCode.Decompiler/IL/Instructions/Block.cs index e8c486dba..479a8f207 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Block.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Block.cs @@ -328,6 +328,7 @@ namespace ICSharpCode.Decompiler.IL foreach (var transform in transforms) { context.CancellationToken.ThrowIfCancellationRequested(); + Debug.Assert(context.IndexOfFirstAlreadyTransformedInstruction <= this.Instructions.Count); context.StepStartGroup(transform.GetType().Name); transform.Run(this, context); this.CheckInvariant(ILPhase.Normal); diff --git a/ICSharpCode.Decompiler/IL/Transforms/BlockTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/BlockTransform.cs index ef1370f07..fdfa34975 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/BlockTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/BlockTransform.cs @@ -53,6 +53,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// public ControlFlowGraph ControlFlowGraph { get; set; } + /// + /// Initially equal to Block.Instructions.Count indicating that nothing has been transformed yet. + /// Set by when another already transformed block is merged into + /// the current block. Subsequent s must update this value, for example, + /// by resetting it to Block.Instructions.Count. will use this value to + /// skip already transformed instructions. + /// + public int IndexOfFirstAlreadyTransformedInstruction { get; set; } + public BlockTransformContext(ILTransformContext context) : base(context) { } @@ -103,6 +112,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms context.ControlFlowNode = cfgNode; context.Block = block; + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; block.RunTransforms(PreOrderTransforms, context); // First, process the children in the dominator tree. @@ -115,6 +125,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms context.ControlFlowNode = cfgNode; context.Block = block; + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; block.RunTransforms(PostOrderTransforms, context); context.StepEndGroup(); } diff --git a/ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs b/ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs index 59a49c78d..4bfa3a996 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs @@ -16,7 +16,6 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using System; using System.Linq; using ICSharpCode.Decompiler.TypeSystem; @@ -32,36 +31,42 @@ namespace ICSharpCode.Decompiler.IL.Transforms this.context = context; if (!context.Settings.AnonymousMethods) return; - for (int i = block.Instructions.Count - 1; i >= 0; i--) + for (int i = context.IndexOfFirstAlreadyTransformedInstruction - 1; i >= 0; i--) { if (block.Instructions[i] is IfInstruction inst) { if (CachedDelegateInitializationWithField(inst)) { block.Instructions.RemoveAt(i); + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; continue; } if (CachedDelegateInitializationWithLocal(inst)) { ILInlining.InlineOneIfPossible(block, i, InliningOptions.Aggressive, context); + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; continue; } if (CachedDelegateInitializationRoslynInStaticWithLocal(inst) || CachedDelegateInitializationRoslynWithLocal(inst)) { block.Instructions.RemoveAt(i); + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; continue; } if (CachedDelegateInitializationVB(inst)) { + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; continue; } if (CachedDelegateInitializationVBWithReturn(inst)) { block.Instructions.RemoveAt(i); + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; continue; } if (CachedDelegateInitializationVBWithClosure(inst)) { + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; continue; } } diff --git a/ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs index 5863db168..084c3bd79 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs @@ -16,12 +16,6 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler.IL.Transforms @@ -35,18 +29,39 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (!context.Settings.LockStatement) return; this.context = context; - for (int i = block.Instructions.Count - 1; i >= 0; i--) + for (int i = context.IndexOfFirstAlreadyTransformedInstruction - 1; i >= 0; i--) { - if (!TransformLockRoslyn(block, i)) - if (!TransformLockV4(block, i)) - if (!TransformLockV4YieldReturn(block, i)) - if (!TransformLockV2(block, i)) - TransformLockMCS(block, i); + bool changed = DoTransform(block, i); + if (changed) + { + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; + } // This happens in some cases: // Use correct index after transformation. if (i >= block.Instructions.Count) i = block.Instructions.Count; } + + bool DoTransform(Block block, int i) + { + if (TransformLockRoslyn(block, i)) + { + return true; + } + if (TransformLockV4(block, i)) + { + return true; + } + if (TransformLockV4YieldReturn(block, i)) + { + return true; + } + if (TransformLockV2(block, i)) + { + return true; + } + return TransformLockMCS(block, i); + } } /// diff --git a/ICSharpCode.Decompiler/IL/Transforms/StatementTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/StatementTransform.cs index 59a8dbbbd..60fd4e325 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/StatementTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/StatementTransform.cs @@ -114,7 +114,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms { var ctx = new StatementTransformContext(context); int pos = 0; - ctx.rerunPosition = block.Instructions.Count - 1; + if (context.IndexOfFirstAlreadyTransformedInstruction == 0) + { + return; + } + ctx.rerunPosition = context.IndexOfFirstAlreadyTransformedInstruction - 1; while (pos >= 0) { if (ctx.rerunPosition != null) diff --git a/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs index 2025d390b..8a61d7931 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs @@ -16,11 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using ICSharpCode.Decompiler.TypeSystem; @@ -35,18 +31,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (!context.Settings.UsingStatement) return; this.context = context; - for (int i = block.Instructions.Count - 1; i >= 0; i--) + for (int i = context.IndexOfFirstAlreadyTransformedInstruction - 1; i >= 0; i--) { if (TransformUsing(block, i)) { + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; continue; } if (TransformUsingVB(block, i)) { + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; continue; } if (TransformAsyncUsing(block, i)) { + context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count; continue; } }