From f99e7036e7c1858eebc138566e299445904e5985 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 24 Feb 2011 16:21:37 +0100 Subject: [PATCH] Add support for array initializers don't use RuntimeHelpers.InitializeArray --- .../ILAst/ArrayInitializers.cs | 105 +++++++++++++----- ICSharpCode.Decompiler/ILAst/Pattern.cs | 7 +- 2 files changed, 81 insertions(+), 31 deletions(-) diff --git a/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs b/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs index 904c7dfa4..7d28743e7 100644 --- a/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs +++ b/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs @@ -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 { 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()) { + 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()) { - 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 operands = new List(); + 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; + } } } diff --git a/ICSharpCode.Decompiler/ILAst/Pattern.cs b/ICSharpCode.Decompiler/ILAst/Pattern.cs index f23c6aa05..075300766 100644 --- a/ICSharpCode.Decompiler/ILAst/Pattern.cs +++ b/ICSharpCode.Decompiler/ILAst/Pattern.cs @@ -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 } } - 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 {