Browse Source

Add support for array initializers don't use RuntimeHelpers.InitializeArray

pull/70/head
Daniel Grunwald 15 years ago
parent
commit
f99e7036e7
  1. 105
      ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs
  2. 7
      ICSharpCode.Decompiler/ILAst/Pattern.cs

105
ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs

@ -2,7 +2,9 @@ @@ -2,7 +2,9 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
namespace Decompiler
@ -14,48 +16,95 @@ namespace Decompiler @@ -14,48 +16,95 @@ namespace Decompiler
{
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));
// 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 - 4; i >= 0; i--) {
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].Arguments[0];
ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0];
int arrayLength = (int)newArrInst.Arguments[0].Operand;
if (!arg1.Match(block.Body[i + 1]))
continue;
if (!arg2.Match(block.Body[i + 2]))
if (arrayLength == 0)
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)
if (arg1.Match(block.Body.ElementAtOrDefault(i + 1)) && arg2.Match(block.Body.ElementAtOrDefault(i + 2))) {
if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 3))) {
HandleStaticallyInitializedArray(arg1, block, i, newArrInst, arrayLength);
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;
}
}
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);
}
}
}
}
static bool IsStoreToArray(ILCode code)
{
switch (code) {
case ILCode.Stelem_Any:
case ILCode.Stelem_I:
case ILCode.Stelem_I1:
case ILCode.Stelem_I2:
case ILCode.Stelem_I4:
case ILCode.Stelem_I8:
case ILCode.Stelem_R4:
case ILCode.Stelem_R8:
case ILCode.Stelem_Ref:
return true;
default:
return false;
}
}
static bool HandleStaticallyInitializedArray(StoreToVariable arg1, ILBlock block, int i, ILExpression newArrInst, int arrayLength)
{
FieldDefinition field = ((ILExpression)block.Body[i + 3]).Arguments[1].Operand as FieldDefinition;
if (field == null || field.InitialValue == null)
return false;
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);
return true;
}
break;
}
return false;
}
}
}

7
ICSharpCode.Decompiler/ILAst/Pattern.cs

@ -11,8 +11,9 @@ namespace Decompiler @@ -11,8 +11,9 @@ namespace Decompiler
bool MatchVariable(ILVariable v);
}
public class StoreToGenerated : ILExpression, IVariablePattern
public class StoreToVariable : ILExpression, IVariablePattern
{
public bool MustBeGenerated;
public ILExpression LastMatch;
public ILVariable LastVariable {
@ -21,14 +22,14 @@ namespace Decompiler @@ -21,14 +22,14 @@ namespace Decompiler
}
}
public StoreToGenerated(ILExpression arg) : base(ILCode.Pattern, null, arg)
public StoreToVariable(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)) {
if (expr != null && expr.Code == ILCode.Stloc && (!MustBeGenerated || ((ILVariable)expr.Operand).IsGenerated) && Match(this.Arguments, expr.Arguments)) {
this.LastMatch = expr;
return true;
} else {

Loading…
Cancel
Save