diff --git a/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs b/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs index 337da8838..8fdb2ba22 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs @@ -38,6 +38,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms ILInstruction copiedExpr; if (block.Instructions[i].MatchStLoc(out v, out copiedExpr)) { if (v.IsSingleDefinition && CanPerformCopyPropagation(v, copiedExpr)) { + context.Step($"Copy propagate {v.Name}", copiedExpr); // un-inline the arguments of the ldArg instruction ILVariable[] uninlinedArgs = new ILVariable[copiedExpr.Children.Count]; for (int j = 0; j < uninlinedArgs.Length; j++) { @@ -60,7 +61,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms } } block.Instructions.RemoveAt(i); - int c = new ILInlining().InlineInto(block, i, aggressive: false); + int c = ILInlining.InlineInto(block, i, aggressive: false, context: context); i -= c + 1; } } diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs index 6cd951a8e..19e844579 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs @@ -31,8 +31,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// public class ILInlining : IILTransform, IBlockTransform { + ILTransformContext context; + public void Run(ILFunction function, ILTransformContext context) { + this.context = context; foreach (var block in function.Descendants.OfType()) { InlineAllInBlock(block); } @@ -41,6 +44,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms public void Run(Block block, BlockTransformContext context) { + this.context = context; InlineAllInBlock(block); } @@ -49,7 +53,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms bool modified = false; int i = 0; while (i < block.Instructions.Count) { - if (InlineOneIfPossible(block, i, aggressive: false)) { + if (InlineOneIfPossible(block, i, aggressive: false, context: context)) { modified = true; i = Math.Max(0, i - 1); // Go back one step @@ -64,13 +68,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// Inlines instructions before pos into block.Instructions[pos]. /// /// The number of instructions that were inlined. - public int InlineInto(Block block, int pos, bool aggressive) + public static int InlineInto(Block block, int pos, bool aggressive, ILTransformContext context) { if (pos >= block.Instructions.Count) return 0; int count = 0; while (--pos >= 0) { - if (InlineOneIfPossible(block, pos, aggressive)) + if (InlineOneIfPossible(block, pos, aggressive, context)) count++; else break; @@ -85,10 +89,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// /// After the operation, pos will point to the new combined instruction. /// - public bool InlineIfPossible(Block block, ref int pos) + public static bool InlineIfPossible(Block block, ref int pos, ILTransformContext context) { - if (InlineOneIfPossible(block, pos, true)) { - pos -= InlineInto(block, pos, false); + if (InlineOneIfPossible(block, pos, true, context)) { + pos -= InlineInto(block, pos, false, context); return true; } return false; @@ -97,8 +101,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// /// Inlines the stloc instruction at block.Instructions[pos] into the next instruction, if possible. /// - public bool InlineOneIfPossible(Block block, int pos, bool aggressive) + public static bool InlineOneIfPossible(Block block, int pos, bool aggressive, ILTransformContext context) { + context.CancellationToken.ThrowIfCancellationRequested(); StLoc stloc = block.Instructions[pos] as StLoc; if (stloc == null || stloc.Variable.Kind == VariableKind.PinnedLocal) return false; @@ -108,7 +113,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms return false; if (v.LoadCount > 1 || v.LoadCount + v.AddressCount != 1) return false; - return InlineOne(stloc, aggressive); + return InlineOne(stloc, aggressive, context); } /// @@ -117,12 +122,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// Note that this method does not check whether 'v' has only one use; /// the caller is expected to validate whether inlining 'v' has any effects on other uses of 'v'. /// - public static bool InlineOne(StLoc stloc, bool aggressive) + public static bool InlineOne(StLoc stloc, bool aggressive, ILTransformContext context) { ILVariable v = stloc.Variable; Block block = (Block)stloc.Parent; int pos = stloc.ChildIndex; - if (DoInline(v, stloc.Value, block.Instructions.ElementAtOrDefault(pos + 1), aggressive)) { + if (DoInline(v, stloc.Value, block.Instructions.ElementAtOrDefault(pos + 1), aggressive, context)) { // Assign the ranges of the stloc instruction: stloc.Value.AddILRange(stloc.ILRange); // Remove the stloc instruction: @@ -134,9 +139,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (SemanticHelper.IsPure(stloc.Value.Flags)) { // Remove completely if the instruction has no effects // (except for reading locals) + context.Step("Remove dead store without side effects", stloc); block.Instructions.RemoveAt(pos); return true; } else if (v.Kind == VariableKind.StackSlot) { + context.Step("Remove dead store, but keep expression", stloc); // Assign the ranges of the stloc instruction: stloc.Value.AddILRange(stloc.ILRange); // Remove the stloc, but keep the inner expression @@ -153,7 +160,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// Note that this method does not check whether 'v' has only one use; /// the caller is expected to validate whether inlining 'v' has any effects on other uses of 'v'. /// - static bool DoInline(ILVariable v, ILInstruction inlinedExpression, ILInstruction next, bool aggressive) + static bool DoInline(ILVariable v, ILInstruction inlinedExpression, ILInstruction next, bool aggressive, ILTransformContext context) { ILInstruction loadInst; if (FindLoadInNext(next, v, inlinedExpression, out loadInst) == true) { @@ -165,7 +172,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (!aggressive && v.Kind != VariableKind.StackSlot && !NonAggressiveInlineInto(next, loadInst, inlinedExpression)) return false; } - + + context.Step($"Inline variable '{v.Name}'", inlinedExpression); // Assign the ranges of the ldloc instruction: inlinedExpression.AddILRange(loadInst.ILRange); diff --git a/ICSharpCode.Decompiler/IL/Transforms/InlineCompilerGeneratedVariables.cs b/ICSharpCode.Decompiler/IL/Transforms/InlineCompilerGeneratedVariables.cs index 549142bf7..14fb5d10d 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/InlineCompilerGeneratedVariables.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/InlineCompilerGeneratedVariables.cs @@ -44,7 +44,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms deadStores.Clear(); if (CanInlineVariable(g.Key, g, storesToInline, deadStores)) { foreach (var stloc in storesToInline) { - ILInlining.InlineOne(stloc, aggressive: false); + ILInlining.InlineOne(stloc, aggressive: false, context: context); } foreach (var stloc in deadStores) { if (SemanticHelper.IsPure(stloc.Flags)) { diff --git a/ICSharpCode.Decompiler/IL/Transforms/LoopingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/LoopingTransform.cs index 4547c582d..9613800b6 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/LoopingTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/LoopingTransform.cs @@ -40,6 +40,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms do { function.ResetDirty(); function.RunTransforms(children, context); + if (function.IsDirty) + context.Step("Function is dirty; running another loop iteration.", function); } while (function.IsDirty); } @@ -66,6 +68,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms do { block.ResetDirty(); block.RunTransforms(children, context); + if (block.IsDirty) + context.Step("Block is dirty; running another loop iteration.", block); } while (block.IsDirty); } diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs index 8be2d65af..a5b85c343 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs @@ -54,17 +54,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms ILInstruction[] values; int initArrayPos; if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out values, out initArrayPos)) { + context.Step($"ForwardScanInitializeArrayRuntimeHelper", inst); var tempStore = context.Function.RegisterVariable(VariableKind.StackSlot, v.Type); var block = BlockFromInitializer(tempStore, elementType, arrayLength, values); body.Instructions[pos].ReplaceWith(new StLoc(v, block)); body.Instructions.RemoveAt(initArrayPos); - new ILInlining().InlineIfPossible(body, ref pos); + ILInlining.InlineIfPossible(body, ref pos, context); return true; } if (arrayLength.Length == 1) { ILVariable finalStore; int instructionsToRemove; if (HandleSimpleArrayInitializer(body, pos + 1, v, arrayLength[0], out finalStore, out values, out instructionsToRemove)) { + context.Step($"HandleSimpleArrayInitializer", inst); var block = new Block(BlockType.ArrayInitializer); var tempStore = context.Function.RegisterVariable(VariableKind.StackSlot, v.Type); block.Instructions.Add(new StLoc(tempStore, new NewArr(elementType, arrayLength.Select(l => new LdcI4(l)).ToArray()))); @@ -79,10 +81,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms body.Instructions[pos].ReplaceWith(new StLoc(finalStore ?? v, block)); RemoveInstructions(body, pos + 1, instructionsToRemove); //body.Instructions.RemoveRange(pos + 1, values.Length + 1); - new ILInlining().InlineIfPossible(body, ref pos); + ILInlining.InlineIfPossible(body, ref pos, context); return true; } if (HandleJaggedArrayInitializer(body, pos + 1, v, arrayLength[0], out finalStore, out values, out instructionsToRemove)) { + context.Step($"HandleJaggedArrayInitializer", inst); var block = new Block(BlockType.ArrayInitializer); var tempStore = context.Function.RegisterVariable(VariableKind.StackSlot, v.Type); block.Instructions.Add(new StLoc(tempStore, new NewArr(elementType, arrayLength.Select(l => new LdcI4(l)).ToArray()))); @@ -90,7 +93,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms block.FinalInstruction = new LdLoc(tempStore); body.Instructions[pos].ReplaceWith(new StLoc(finalStore, block)); RemoveInstructions(body, pos + 1, instructionsToRemove); - new ILInlining().InlineIfPossible(body, ref pos); + ILInlining.InlineIfPossible(body, ref pos, context); return true; } } @@ -265,7 +268,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms var block = BlockFromInitializer(v, arrayType, length, values); body.Instructions[pos].ReplaceWith(new StLoc(v, block)); body.Instructions.RemoveAt(initArrayPos); - new ILInlining().InlineIfPossible(body, ref pos); + ILInlining.InlineIfPossible(body, ref pos, context); return true; } } diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs index f602bc4c7..f9d984b2d 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs @@ -68,7 +68,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// --> /// stloc s(stobj (..., value)) /// - static bool TransformInlineAssignmentStObj(Block block, int i) + bool TransformInlineAssignmentStObj(Block block, int i) { var inst = block.Instructions[i] as StLoc; // in some cases it can be a compiler-generated local @@ -92,15 +92,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms TransformInlineAssignmentLocal(block, i); return false; } + context.Step("Inline assignment to instance field", fieldStore); local = localStore.Variable; block.Instructions.RemoveAt(i + 1); } else if (nextInst is StObj) { // static fields fieldStore = (StObj)nextInst; if (!fieldStore.Value.MatchLdLoc(inst.Variable)) return false; + context.Step("Inline assignment to static field", fieldStore); local = inst.Variable; replacement = new StObj(fieldStore.Target, inst.Value, fieldStore.Type); - } else return false; + } else { + return false; + } block.Instructions.RemoveAt(i + 1); inst.ReplaceWith(new StLoc(local, replacement)); return true; @@ -121,7 +125,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// --> /// ... compound.op.new(callvirt(getter), value) ... /// - static bool TransformInlineAssignmentCall(Block block, int i) + bool TransformInlineAssignmentCall(Block block, int i) { var inst = block.Instructions[i] as StLoc; // in some cases it can be a compiler-generated local @@ -150,6 +154,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms var usages = next.Descendants.Where(d => d.MatchLdLoc(localVariable)).ToArray(); if (usages.Length != 1) return false; + context.Step($"Compound assignment to '{owner.Name}'", setterCall); block.Instructions.RemoveAt(i + 1); block.Instructions.RemoveAt(i); usages[0].ReplaceWith(new CompoundAssignmentInstruction(binary.Operator, getterCall, binary.Right, @@ -163,7 +168,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// --> /// stloc s(stloc l(value)) /// - static void TransformInlineAssignmentLocal(Block block, int i) + void TransformInlineAssignmentLocal(Block block, int i) { var inst = block.Instructions[i] as StLoc; var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; @@ -171,6 +176,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms return; if (nextInst.Variable.Kind == VariableKind.StackSlot || !nextInst.Value.MatchLdLoc(inst.Variable)) return; + context.Step("Inline assignment to local variable", inst); var value = inst.Value; var var = nextInst.Variable; var stackVar = inst.Variable; @@ -185,7 +191,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// --> /// use ldaddress instead of ldloc s /// - static bool InlineLdAddressUsages(Block block, int i) + bool InlineLdAddressUsages(Block block, int i) { var inst = block.Instructions[i] as StLoc; if (inst == null || inst.Variable.Kind != VariableKind.StackSlot || !(inst.Value is LdElema || inst.Value is LdFlda || inst.Value is LdsFlda)) @@ -201,6 +207,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms .Cast().ToArray(); if (affectedUsages.Length == 0 || affectedUsages.Any(ins => !(ins.Parent is StObj || ins.Parent is LdObj))) return false; + context.Step($"InlineLdAddressUsage", inst); foreach (var usage in affectedUsages) { usage.ReplaceWith(valueToCopy.Clone()); } @@ -228,6 +235,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms return false; if ((binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub) || !binary.Left.MatchLdLoc(inst.Variable) || !binary.Right.MatchLdcI4(1)) return false; + context.Step($"TransformPostIncDecOperator", inst); var tempStore = context.Function.RegisterVariable(VariableKind.StackSlot, inst.Variable.Type); var assignment = new Block(BlockType.CompoundOperator); assignment.Instructions.Add(new StLoc(tempStore, new LdLoc(nextInst.Variable))); @@ -245,7 +253,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// --> /// stloc l(compound.op.old(ldobj(ldaddress), ldc.i4 1)) /// - static bool TransformPostIncDecOperatorOnAddress(Block block, int i) + bool TransformPostIncDecOperatorOnAddress(Block block, int i) { var inst = block.Instructions[i] as StLoc; var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; @@ -264,6 +272,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (binary == null || !binary.Left.MatchLdLoc(nextInst.Variable) || !binary.Right.MatchLdcI4(1) || (binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub)) return false; + context.Step($"TransformPostIncDecOperator", inst); var assignment = new CompoundAssignmentInstruction(binary.Operator, new LdObj(inst.Value, targetType), binary.Right, targetType, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToOldValue); stobj.ReplaceWith(new StLoc(nextInst.Variable, assignment)); block.Instructions.RemoveAt(i + 1); @@ -278,7 +287,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// --> /// stloc l(compound.op.old(ldobj(ldflda(ldflda)), ldc.i4 1)) /// - static bool TransformCSharp4PostIncDecOperatorOnAddress(Block block, int i) + bool TransformCSharp4PostIncDecOperatorOnAddress(Block block, int i) { var baseFieldAddress = block.Instructions[i] as StLoc; var fieldValue = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; @@ -313,6 +322,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (binary == null || !binary.Left.MatchLdLoc(fieldValue.Variable) || !binary.Right.MatchLdcI4(1) || (binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub)) return false; + context.Step($"TransformCSharp4PostIncDecOperatorOnAddress", baseFieldAddress); var assignment = new CompoundAssignmentInstruction(binary.Operator, new LdObj(baseAddress, t), binary.Right, t, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToOldValue); stobj.ReplaceWith(new StLoc(fieldValueCopyToLocal.Variable, assignment)); block.Instructions.RemoveAt(i + 2); @@ -326,7 +336,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// --> /// stloc s(compound.op.old(ldobj(ldsflda), ldc.i4 1)) /// - static bool TransformPostIncDecOnStaticField(Block block, int i) + bool TransformPostIncDecOnStaticField(Block block, int i) { var inst = block.Instructions[i] as StLoc; var stobj = block.Instructions.ElementAtOrDefault(i + 1) as StObj; @@ -342,6 +352,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms var binary = stobj.Value as BinaryNumericInstruction; if (binary == null || !binary.Left.MatchLdLoc(inst.Variable) || !binary.Right.MatchLdcI4(1)) return false; + context.Step($"TransformPostIncDecOnStaticField", inst); var assignment = new CompoundAssignmentInstruction(binary.Operator, inst.Value, binary.Right, type, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToOldValue); stobj.ReplaceWith(new StLoc(inst.Variable, assignment)); return true;