Browse Source

Add support for array initializers.

pull/70/head
Daniel Grunwald 15 years ago
parent
commit
7de3cf9bc4
  1. 8
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  3. 61
      ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs
  4. 4
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  5. 21
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  6. 5
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  7. 102
      ICSharpCode.Decompiler/ILAst/Pattern.cs
  8. 6
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  9. 36
      ICSharpCode.Decompiler/Tests/ArrayInitializers.cs
  10. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  11. 4
      ILSpy/ILAstLanguage.cs

8
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -334,6 +334,14 @@ namespace Decompiler @@ -334,6 +334,14 @@ namespace Decompiler
ace.Arguments.Add(arg1);
return ace;
}
case (Code)ILCode.InitArray:
{
var ace = new Ast.ArrayCreateExpression();
ace.Type = operandAsTypeRef;
ace.Initializer = new ArrayInitializerExpression();
ace.Initializer.Elements.AddRange(args);
return ace;
}
case Code.Ldlen:
return arg1.Member("Length");
case Code.Ldelem_I:

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -89,10 +89,12 @@ @@ -89,10 +89,12 @@
<Compile Include="FlowAnalysis\SsaVariable.cs" />
<Compile Include="FlowAnalysis\TransformToSsa.cs" />
<Compile Include="GraphVizGraph.cs" />
<Compile Include="ILAst\ArrayInitializers.cs" />
<Compile Include="ILAst\ILAstBuilder.cs" />
<Compile Include="ILAst\ILAstOptimizer.cs" />
<Compile Include="ILAst\ILAstTypes.cs" />
<Compile Include="ILAst\ILCodes.cs" />
<Compile Include="ILAst\Pattern.cs" />
<Compile Include="ILAst\TypeAnalysis.cs" />
<Compile Include="ITextOutput.cs" />
<Compile Include="Options.cs" />

61
ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
// 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 Mono.Cecil;
namespace Decompiler
{
/// <summary>
/// IL AST transformation that introduces array initializers.
/// </summary>
public class ArrayInitializers
{
public static void Transform(ILBlock method)
{
var newArrPattern = new StoreToGenerated(new ILExpression(
ILCode.Dup, null,
new ILExpression(ILCode.Newarr, ILExpression.AnyOperand, new ILExpression(ILCode.Ldc_I4, ILExpression.AnyOperand))
));
var arg1 = new StoreToGenerated(new LoadFromVariable(newArrPattern));
var arg2 = new StoreToGenerated(new LoadFromVariable(newArrPattern));
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 - 4; i >= 0; i--) {
if (!newArrPattern.Match(block.Body[i]))
continue;
ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0].Arguments[0];
int arrayLength = (int)newArrInst.Arguments[0].Operand;
if (!arg1.Match(block.Body[i + 1]))
continue;
if (!arg2.Match(block.Body[i + 2]))
continue;
if (initializeArrayPattern.Match(block.Body[i + 3])) {
FieldDefinition field = ((ILExpression)block.Body[i+3]).Arguments[1].Operand as FieldDefinition;
if (field == null || field.InitialValue == null)
continue;
switch (TypeAnalysis.GetTypeCode(newArrInst.Operand as TypeReference)) {
case TypeCode.Int32:
case TypeCode.UInt32:
if (field.InitialValue.Length == arrayLength * 4) {
ILExpression[] newArr = new ILExpression[arrayLength];
for (int j = 0; j < newArr.Length; j++) {
newArr[j] = new ILExpression(ILCode.Ldc_I4, BitConverter.ToInt32(field.InitialValue, j * 4));
}
block.Body[i] = new ILExpression(ILCode.Stloc, arg1.LastVariable, new ILExpression(ILCode.InitArray, newArrInst.Operand, newArr));
block.Body.RemoveRange(i + 1, 3);
}
continue;
default:
continue;
}
}
}
}
}
}
}

4
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -17,6 +17,7 @@ namespace Decompiler.ControlFlow @@ -17,6 +17,7 @@ namespace Decompiler.ControlFlow
FlattenNestedMovableBlocks,
SimpleGotoRemoval,
RemoveDeadLabels,
HandleArrayInitializers,
TypeInference,
None
}
@ -64,6 +65,9 @@ namespace Decompiler.ControlFlow @@ -64,6 +65,9 @@ namespace Decompiler.ControlFlow
if (abortBeforeStep == ILAstOptimizationStep.RemoveDeadLabels) return;
RemoveDeadLabels(method);
if (abortBeforeStep == ILAstOptimizationStep.HandleArrayInitializers) return;
ArrayInitializers.Transform(method);
if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
TypeAnalysis.Run(context, method);
}

21
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -207,6 +207,8 @@ namespace Decompiler @@ -207,6 +207,8 @@ namespace Decompiler
public TypeReference ExpectedType { get; set; }
public TypeReference InferredType { get; set; }
public static readonly object AnyOperand = new object();
public ILExpression(ILCode code, object operand, params ILExpression[] args)
{
this.Code = code;
@ -269,6 +271,25 @@ namespace Decompiler @@ -269,6 +271,25 @@ namespace Decompiler
return ranges;
}
public virtual bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
return expr != null && this.Code == expr.Code
&& (this.Operand == AnyOperand || object.Equals(this.Operand, expr.Operand))
&& Match(this.Arguments, expr.Arguments);
}
protected static bool Match(IList<ILExpression> a, IList<ILExpression> b)
{
if (a.Count != b.Count)
return false;
for (int i = 0; i < a.Count; i++) {
if (!a[i].Match(b[i]))
return false;
}
return true;
}
public override void WriteTo(ITextOutput output)
{
if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) {

5
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -257,7 +257,10 @@ namespace Decompiler @@ -257,7 +257,10 @@ namespace Decompiler
Ldexception, // Operand holds the CatchType for catch handler, null for filter
LogicNot,
BrLogicAnd,
BrLogicOr
BrLogicOr,
InitArray, // Array Initializer
Pattern // used for ILAst pattern nodes
}
public static class ILCodeUtil

102
ICSharpCode.Decompiler/ILAst/Pattern.cs

@ -0,0 +1,102 @@ @@ -0,0 +1,102 @@
// 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 Mono.Cecil;
namespace Decompiler
{
public interface IVariablePattern
{
bool MatchVariable(ILVariable v);
}
public class StoreToGenerated : ILExpression, IVariablePattern
{
public ILExpression LastMatch;
public ILVariable LastVariable {
get {
return LastMatch != null ? LastMatch.Operand as ILVariable : null;
}
}
public StoreToGenerated(ILExpression arg) : base(ILCode.Pattern, null, arg)
{
}
public override bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
if (expr != null && expr.Code == ILCode.Stloc && ((ILVariable)expr.Operand).IsGenerated && Match(this.Arguments, expr.Arguments)) {
this.LastMatch = expr;
return true;
} else {
return false;
}
}
bool IVariablePattern.MatchVariable(ILVariable v)
{
return v == LastMatch.Operand;
}
}
public class LoadFromVariable : ILExpression
{
IVariablePattern v;
public LoadFromVariable(IVariablePattern v) : base(ILCode.Pattern, null)
{
this.v = v;
}
public override bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
return expr != null && expr.Code == ILCode.Ldloc && v.MatchVariable(expr.Operand as ILVariable);
}
}
public class AnyILExpression : ILExpression
{
public ILExpression LastMatch;
public AnyILExpression() : base(ILCode.Pattern, null)
{
}
public override bool Match(ILNode other)
{
if (other is ILExpression) {
LastMatch = (ILExpression)other;
return true;
} else {
return false;
}
}
}
public class ILCall : ILExpression
{
string fullClassName;
string methodName;
public ILCall(string fullClassName, string methodName, params ILExpression[] args) : base(ILCode.Pattern, null, args)
{
this.fullClassName = fullClassName;
this.methodName = methodName;
}
public override bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
if (expr != null && expr.Code == ILCode.Call) {
MethodReference r = (MethodReference)expr.Operand;
if (r.Name == methodName && r.DeclaringType.FullName == fullClassName)
return Match(this.Arguments, expr.Arguments);
}
return false;
}
}
}

6
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -310,6 +310,12 @@ namespace Decompiler @@ -310,6 +310,12 @@ namespace Decompiler
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Int32);
return new ArrayType((TypeReference)expr.Operand);
case ILCode.InitArray:
if (forceInferChildren) {
foreach (ILExpression arg in expr.Arguments)
InferTypeForExpression(arg, (TypeReference)expr.Operand);
}
return new ArrayType((TypeReference)expr.Operand);
case ILCode.Ldlen:
return typeSystem.Int32;
case ILCode.Ldelem_U1:

36
ICSharpCode.Decompiler/Tests/ArrayInitializers.cs

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
// 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;
public class ArrayInitializers
{
// Helper methods used to ensure array initializers used within expressions work correctly
static void X(object a, object b)
{
}
static object Y()
{
return null;
}
public static void Array1()
{
X(Y(), new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
}
public static void Array2(int a, int b, int c)
{
X(Y(), new int[] { a, b, c });
}
public static void NestedArray(int a, int b, int c)
{
X(Y(), new int[][] {
new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
new int[] { a, b, c },
new int[] { 1, 2, 3, 4, 5, 6 }
});
}
}

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -48,6 +48,7 @@ @@ -48,6 +48,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ArrayInitializers.cs" />
<Compile Include="DelegateConstruction.cs" />
<Compile Include="ExceptionHandling.cs" />
<Compile Include="MultidimensionalArray.cs" />

4
ILSpy/ILAstLanguage.cs

@ -47,6 +47,10 @@ namespace ICSharpCode.ILSpy @@ -47,6 +47,10 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
if (!method.HasBody) {
return;
}
ILAstBuilder astBuilder = new ILAstBuilder();
ILBlock ilMethod = new ILBlock();
ilMethod.Body = astBuilder.Build(method, inlineVariables);

Loading…
Cancel
Save