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
} }
PickBetterBlockExit(block, ifInst); PickBetterBlockExit(block, ifInst);
OrderIfBlocks(ifInst); OrderIfBlocks(ifInst);
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
} }
/// <summary> /// <summary>
@ -150,6 +151,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// The targetBlock was already processed, and is ready to embed // The targetBlock was already processed, and is ready to embed
var targetBlock = ((Branch)exitInst).TargetBlock; var targetBlock = ((Branch)exitInst).TargetBlock;
block.Instructions.RemoveAt(block.Instructions.Count - 1); block.Instructions.RemoveAt(block.Instructions.Count - 1);
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
block.Instructions.AddRange(targetBlock.Instructions); block.Instructions.AddRange(targetBlock.Instructions);
targetBlock.Remove(); targetBlock.Remove();

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

@ -328,6 +328,7 @@ namespace ICSharpCode.Decompiler.IL
foreach (var transform in transforms) foreach (var transform in transforms)
{ {
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
Debug.Assert(context.IndexOfFirstAlreadyTransformedInstruction <= this.Instructions.Count);
context.StepStartGroup(transform.GetType().Name); context.StepStartGroup(transform.GetType().Name);
transform.Run(this, context); transform.Run(this, context);
this.CheckInvariant(ILPhase.Normal); this.CheckInvariant(ILPhase.Normal);

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

@ -53,6 +53,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary> /// </summary>
public ControlFlowGraph ControlFlowGraph { get; set; } 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) public BlockTransformContext(ILTransformContext context) : base(context)
{ {
} }
@ -103,6 +112,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.ControlFlowNode = cfgNode; context.ControlFlowNode = cfgNode;
context.Block = block; context.Block = block;
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
block.RunTransforms(PreOrderTransforms, context); block.RunTransforms(PreOrderTransforms, context);
// First, process the children in the dominator tree. // First, process the children in the dominator tree.
@ -115,6 +125,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.ControlFlowNode = cfgNode; context.ControlFlowNode = cfgNode;
context.Block = block; context.Block = block;
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
block.RunTransforms(PostOrderTransforms, context); block.RunTransforms(PostOrderTransforms, context);
context.StepEndGroup(); context.StepEndGroup();
} }

9
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 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -32,36 +31,42 @@ namespace ICSharpCode.Decompiler.IL.Transforms
this.context = context; this.context = context;
if (!context.Settings.AnonymousMethods) if (!context.Settings.AnonymousMethods)
return; 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 (block.Instructions[i] is IfInstruction inst)
{ {
if (CachedDelegateInitializationWithField(inst)) if (CachedDelegateInitializationWithField(inst))
{ {
block.Instructions.RemoveAt(i); block.Instructions.RemoveAt(i);
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
continue; continue;
} }
if (CachedDelegateInitializationWithLocal(inst)) if (CachedDelegateInitializationWithLocal(inst))
{ {
ILInlining.InlineOneIfPossible(block, i, InliningOptions.Aggressive, context); ILInlining.InlineOneIfPossible(block, i, InliningOptions.Aggressive, context);
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
continue; continue;
} }
if (CachedDelegateInitializationRoslynInStaticWithLocal(inst) || CachedDelegateInitializationRoslynWithLocal(inst)) if (CachedDelegateInitializationRoslynInStaticWithLocal(inst) || CachedDelegateInitializationRoslynWithLocal(inst))
{ {
block.Instructions.RemoveAt(i); block.Instructions.RemoveAt(i);
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
continue; continue;
} }
if (CachedDelegateInitializationVB(inst)) if (CachedDelegateInitializationVB(inst))
{ {
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
continue; continue;
} }
if (CachedDelegateInitializationVBWithReturn(inst)) if (CachedDelegateInitializationVBWithReturn(inst))
{ {
block.Instructions.RemoveAt(i); block.Instructions.RemoveAt(i);
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
continue; continue;
} }
if (CachedDelegateInitializationVBWithClosure(inst)) if (CachedDelegateInitializationVBWithClosure(inst))
{ {
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
continue; continue;
} }
} }

39
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 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL.Transforms namespace ICSharpCode.Decompiler.IL.Transforms
@ -35,18 +29,39 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!context.Settings.LockStatement) if (!context.Settings.LockStatement)
return; return;
this.context = context; 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)) bool changed = DoTransform(block, i);
if (!TransformLockV4(block, i)) if (changed)
if (!TransformLockV4YieldReturn(block, i)) {
if (!TransformLockV2(block, i)) context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
TransformLockMCS(block, i); }
// This happens in some cases: // This happens in some cases:
// Use correct index after transformation. // Use correct index after transformation.
if (i >= block.Instructions.Count) if (i >= block.Instructions.Count)
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> /// <summary>

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

@ -114,7 +114,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
var ctx = new StatementTransformContext(context); var ctx = new StatementTransformContext(context);
int pos = 0; int pos = 0;
ctx.rerunPosition = block.Instructions.Count - 1; if (context.IndexOfFirstAlreadyTransformedInstruction == 0)
{
return;
}
ctx.rerunPosition = context.IndexOfFirstAlreadyTransformedInstruction - 1;
while (pos >= 0) while (pos >= 0)
{ {
if (ctx.rerunPosition != null) if (ctx.rerunPosition != null)

9
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 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -35,18 +31,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!context.Settings.UsingStatement) if (!context.Settings.UsingStatement)
return; return;
this.context = context; 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)) if (TransformUsing(block, i))
{ {
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
continue; continue;
} }
if (TransformUsingVB(block, i)) if (TransformUsingVB(block, i))
{ {
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
continue; continue;
} }
if (TransformAsyncUsing(block, i)) if (TransformAsyncUsing(block, i))
{ {
context.IndexOfFirstAlreadyTransformedInstruction = block.Instructions.Count;
continue; continue;
} }
} }

Loading…
Cancel
Save