mirror of https://github.com/icsharpcode/ILSpy.git
11 changed files with 327 additions and 79 deletions
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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 } |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue