Browse Source

#3075: Avoid processing already-transformed blocks by introducing BlockTransformContext.IndexOfFirstAlreadyTransformedInstruction, which allows us to track already transformed instructions after a block has been merged into another by ConditionDetection.

pull/3111/head
Siegfried Pammer 2 years ago
parent
commit
0a2037ae1f
  1. 2
      ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs
  2. 1
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  3. 11
      ICSharpCode.Decompiler/IL/Transforms/BlockTransform.cs
  4. 9
      ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs
  5. 39
      ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs
  6. 6
      ICSharpCode.Decompiler/IL/Transforms/StatementTransform.cs
  7. 9
      ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

2
ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs

@ -93,6 +93,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -93,6 +93,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
}
PickBetterBlockExit(block, ifInst);
OrderIfBlocks(ifInst);
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
}
/// <summary>
@ -150,6 +151,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -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();

1
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -328,6 +328,7 @@ namespace ICSharpCode.Decompiler.IL @@ -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);

11
ICSharpCode.Decompiler/IL/Transforms/BlockTransform.cs

@ -53,6 +53,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -53,6 +53,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
public ControlFlowGraph ControlFlowGraph { get; set; }
/// <summary>
/// Initially equal to Block.Instructions.Count indicating that nothing has been transformed yet.
/// Set by <see cref="ConditionDetection"/> when another already transformed block is merged into
/// the current block. Subsequent <see cref="IBlockTransform"/>s must update this value, for example,
/// by resetting it to Block.Instructions.Count. <see cref="StatementTransform"/> will use this value to
/// skip already transformed instructions.
/// </summary>
public int IndexOfFirstAlreadyTransformedInstruction { get; set; }
public BlockTransformContext(ILTransformContext context) : base(context)
{
}
@ -103,6 +112,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -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 @@ -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();
}

9
ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs

@ -16,7 +16,6 @@ @@ -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 @@ -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;
}
}

39
ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs

@ -16,12 +16,6 @@ @@ -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 @@ -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);
}
}
/// <summary>

6
ICSharpCode.Decompiler/IL/Transforms/StatementTransform.cs

@ -114,7 +114,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -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)

9
ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

@ -16,11 +16,7 @@ @@ -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 @@ -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;
}
}

Loading…
Cancel
Save