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);
+ }
+ }
+ }
+ }
+ }
+}