|
|
|
@ -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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|