Browse Source

Refactor ArrayInitializers into a general peephole-transformation step.

pull/70/head
Daniel Grunwald 15 years ago
parent
commit
ee105aeb3c
  1. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  2. 80
      ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs
  3. 12
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  4. 44
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -93,6 +93,7 @@ @@ -93,6 +93,7 @@
<Compile Include="ILAst\ILCodes.cs" />
<Compile Include="ILAst\ILInlining.cs" />
<Compile Include="ILAst\Pattern.cs" />
<Compile Include="ILAst\PeepholeTransform.cs" />
<Compile Include="ILAst\TypeAnalysis.cs" />
<Compile Include="ITextOutput.cs" />
<Compile Include="PlainTextOutput.cs" />

80
ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs

@ -12,62 +12,52 @@ namespace Decompiler @@ -12,62 +12,52 @@ namespace Decompiler
/// <summary>
/// IL AST transformation that introduces array initializers.
/// </summary>
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<ILExpression>()) {
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<ILBlock>()) {
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<ILExpression> operands = new List<ILExpression>();
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<ILExpression> operands = new List<ILExpression>();
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)

12
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -19,7 +19,7 @@ namespace Decompiler.ControlFlow @@ -19,7 +19,7 @@ namespace Decompiler.ControlFlow
GotoRemoval,
DuplicateReturns,
FlattenIfStatements,
HandleArrayInitializers,
PeepholeTransforms,
TypeInference,
None
}
@ -76,8 +76,8 @@ namespace Decompiler.ControlFlow @@ -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 @@ -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))

44
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -0,0 +1,44 @@ @@ -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);
/// <summary>
/// Handles peephole transformations on the ILAst.
/// </summary>
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<ILExpression>()) {
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<ILNode>(method, c => c != null ? c.GetChildren() : null).OfType<ILBlock>()) {
// 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);
}
}
}
}
}
}
Loading…
Cancel
Save