From ee105aeb3cd90ead8f44d5294895009cd5443dd0 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 3 Mar 2011 18:20:05 +0100 Subject: [PATCH] Refactor ArrayInitializers into a general peephole-transformation step. --- .../ICSharpCode.Decompiler.csproj | 1 + .../ILAst/ArrayInitializers.cs | 80 ++++++++----------- .../ILAst/ILAstOptimizer.cs | 12 +-- .../ILAst/PeepholeTransform.cs | 44 ++++++++++ 4 files changed, 86 insertions(+), 51 deletions(-) create mode 100644 ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 57d9af472..3896d43f1 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -93,6 +93,7 @@ + diff --git a/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs b/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs index 2366d27e8..4c80e21d6 100644 --- a/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs +++ b/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs @@ -12,62 +12,52 @@ namespace Decompiler /// /// IL AST transformation that introduces array initializers. /// - public class ArrayInitializers + public static class ArrayInitializers { - public static void Transform(ILBlock method) + public static PeepholeTransform Transform(ILBlock method) { - // TODO: move this somewhere else - // Eliminate 'dups': - foreach (ILExpression expr in method.GetSelfAndChildrenRecursive()) { - for (int i = 0; i < expr.Arguments.Count; i++) { - if (expr.Arguments[i].Code == ILCode.Dup) - expr.Arguments[i] = expr.Arguments[i].Arguments[0]; - } - } - var newArrPattern = new StoreToVariable(new ILExpression(ILCode.Newarr, ILExpression.AnyOperand, new ILExpression(ILCode.Ldc_I4, ILExpression.AnyOperand))); var arg1 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true }; var arg2 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true }; var initializeArrayPattern = new ILCall( "System.Runtime.CompilerServices.RuntimeHelpers", "InitializeArray", new LoadFromVariable(arg1), new ILExpression(ILCode.Ldtoken, ILExpression.AnyOperand)); - foreach (ILBlock block in method.GetSelfAndChildrenRecursive()) { - for (int i = block.Body.Count - 1; i >= 0; i--) { - if (!newArrPattern.Match(block.Body[i])) - continue; - ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0]; - int arrayLength = (int)newArrInst.Arguments[0].Operand; - if (arrayLength == 0) - continue; - if (arg1.Match(block.Body.ElementAtOrDefault(i + 1)) && arg2.Match(block.Body.ElementAtOrDefault(i + 2))) { - if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 3))) { - if (HandleStaticallyInitializedArray(arg2, block, i, newArrInst, arrayLength)) { - i -= ILInlining.InlineInto(block, i + 1, method) - 1; - } - continue; + + return delegate(ILBlock block, ref int i) { + if (!newArrPattern.Match(block.Body[i])) + return; + ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0]; + int arrayLength = (int)newArrInst.Arguments[0].Operand; + if (arrayLength == 0) + return; + if (arg1.Match(block.Body.ElementAtOrDefault(i + 1)) && arg2.Match(block.Body.ElementAtOrDefault(i + 2))) { + if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 3))) { + if (HandleStaticallyInitializedArray(arg2, block, i, newArrInst, arrayLength)) { + i -= ILInlining.InlineInto(block, i + 1, method) - 1; } - } - if (i + 1 + arrayLength > block.Body.Count) - continue; - List operands = new List(); - for (int j = 0; j < arrayLength; j++) { - ILExpression expr = block.Body[i + 1 + j] as ILExpression; - if (expr == null || !IsStoreToArray(expr.Code)) - break; - if (!(expr.Arguments[0].Code == ILCode.Ldloc && expr.Arguments[0].Operand == newArrPattern.LastVariable)) - break; - if (!(expr.Arguments[1].Code == ILCode.Ldc_I4 && (int)expr.Arguments[1].Operand == j)) - break; - operands.Add(expr.Arguments[2]); - } - if (operands.Count == arrayLength) { - ((ILExpression)block.Body[i]).Arguments[0] = new ILExpression( - ILCode.InitArray, newArrInst.Operand, operands.ToArray()); - block.Body.RemoveRange(i + 1, arrayLength); - i -= ILInlining.InlineInto(block, i + 1, method) - 1; + return; } } - } + if (i + 1 + arrayLength > block.Body.Count) + return; + List operands = new List(); + for (int j = 0; j < arrayLength; j++) { + ILExpression expr = block.Body[i + 1 + j] as ILExpression; + if (expr == null || !IsStoreToArray(expr.Code)) + break; + if (!(expr.Arguments[0].Code == ILCode.Ldloc && expr.Arguments[0].Operand == newArrPattern.LastVariable)) + break; + if (!(expr.Arguments[1].Code == ILCode.Ldc_I4 && (int)expr.Arguments[1].Operand == j)) + break; + operands.Add(expr.Arguments[2]); + } + if (operands.Count == arrayLength) { + ((ILExpression)block.Body[i]).Arguments[0] = new ILExpression( + ILCode.InitArray, newArrInst.Operand, operands.ToArray()); + block.Body.RemoveRange(i + 1, arrayLength); + i -= ILInlining.InlineInto(block, i + 1, method) - 1; + } + }; } static bool IsStoreToArray(ILCode code) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index f214dc48a..58f54d05f 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -19,7 +19,7 @@ namespace Decompiler.ControlFlow GotoRemoval, DuplicateReturns, FlattenIfStatements, - HandleArrayInitializers, + PeepholeTransforms, TypeInference, None } @@ -76,8 +76,8 @@ namespace Decompiler.ControlFlow if (abortBeforeStep == ILAstOptimizationStep.FlattenIfStatements) return; FlattenIfStatements(method); - if (abortBeforeStep == ILAstOptimizationStep.HandleArrayInitializers) return; - ArrayInitializers.Transform(method); + if (abortBeforeStep == ILAstOptimizationStep.PeepholeTransforms) return; + PeepholeTransforms.Run(context, method); if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return; TypeAnalysis.Run(context, method); @@ -562,9 +562,9 @@ namespace Decompiler.ControlFlow DefaultGoto = block.FallthoughGoto }; result.Add(new ILBasicBlock() { - EntryLabel = block.EntryLabel, // Keep the entry label - Body = { ilSwitch } - }); + EntryLabel = block.EntryLabel, // Keep the entry label + Body = { ilSwitch } + }); // Remove the item so that it is not picked up as content if (!scope.Remove(node)) diff --git a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs new file mode 100644 index 000000000..d1fd94012 --- /dev/null +++ b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs @@ -0,0 +1,44 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Linq; +using ICSharpCode.NRefactory.Utils; + +namespace Decompiler +{ + public delegate void PeepholeTransform(ILBlock block, ref int i); + + /// + /// Handles peephole transformations on the ILAst. + /// + public static class PeepholeTransforms + { + public static void Run(DecompilerContext context, ILBlock method) + { + // TODO: move this somewhere else + // Eliminate 'dups': + foreach (ILExpression expr in method.GetSelfAndChildrenRecursive()) { + for (int i = 0; i < expr.Arguments.Count; i++) { + if (expr.Arguments[i].Code == ILCode.Dup) + expr.Arguments[i] = expr.Arguments[i].Arguments[0]; + } + } + + PeepholeTransform[] transforms = { + ArrayInitializers.Transform(method) + }; + // Traverse in post order so that nested blocks are transformed first. This is required so that + // patterns on the parent block can assume that all nested blocks are already transformed. + foreach (var block in TreeTraversal.PostOrder(method, c => c != null ? c.GetChildren() : null).OfType()) { + // go through the instructions in reverse so that + for (int i = block.Body.Count - 1; i >= 0; i--) { + context.CancellationToken.ThrowIfCancellationRequested(); + foreach (var t in transforms) { + t(block, ref i); + } + } + } + } + } +}