diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index c226d6296..a18607f14 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -94,6 +94,7 @@ + diff --git a/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs b/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs index 7d28743e7..2366d27e8 100644 --- a/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs +++ b/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs @@ -41,7 +41,9 @@ namespace Decompiler continue; 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); + if (HandleStaticallyInitializedArray(arg2, block, i, newArrInst, arrayLength)) { + i -= ILInlining.InlineInto(block, i + 1, method) - 1; + } continue; } } @@ -62,6 +64,7 @@ namespace Decompiler ((ILExpression)block.Body[i]).Arguments[0] = new ILExpression( ILCode.InitArray, newArrInst.Operand, operands.ToArray()); block.Body.RemoveRange(i + 1, arrayLength); + i -= ILInlining.InlineInto(block, i + 1, method) - 1; } } } @@ -85,7 +88,7 @@ namespace Decompiler } } - static bool HandleStaticallyInitializedArray(StoreToVariable arg1, ILBlock block, int i, ILExpression newArrInst, int arrayLength) + static bool HandleStaticallyInitializedArray(StoreToVariable arg2, 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) @@ -98,7 +101,7 @@ namespace Decompiler 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[i] = new ILExpression(ILCode.Stloc, arg2.LastVariable, new ILExpression(ILCode.InitArray, newArrInst.Operand, newArr)); block.Body.RemoveRange(i + 1, 3); return true; } diff --git a/ICSharpCode.Decompiler/ILAst/ILInlining.cs b/ICSharpCode.Decompiler/ILAst/ILInlining.cs new file mode 100644 index 000000000..75910a7d1 --- /dev/null +++ b/ICSharpCode.Decompiler/ILAst/ILInlining.cs @@ -0,0 +1,92 @@ +// 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.Diagnostics; +using System.Linq; + +namespace Decompiler +{ + /// + /// Performs inlining transformations. + /// + public class ILInlining + { + /// + /// Inlines instructions before pos into block.Body[pos]. + /// + /// The number of instructions that were inlined. + public static int InlineInto(ILBlock block, int pos, ILBlock method) + { + int count = 0; + while (--pos >= 0) { + ILExpression expr = block.Body[pos] as ILExpression; + if (expr == null || expr.Code != ILCode.Stloc) + break; + if (InlineIfPossible(block, pos, method)) + count++; + else + break; + } + return count; + } + + /// + /// Inlines the stloc instruction at block.Body[pos] into the next instruction, if possible. + /// + public static bool InlineIfPossible(ILBlock block, int pos, ILBlock method) + { + if (InlineIfPossible((ILExpression)block.Body[pos], block.Body.ElementAtOrDefault(pos+1), method)) { + block.Body.RemoveAt(pos); + return true; + } + return false; + } + + /// + /// Inlines 'expr' into 'next', if possible. + /// + public static bool InlineIfPossible(ILExpression expr, ILNode next, ILBlock method) + { + if (expr.Code != ILCode.Stloc) + throw new ArgumentException("expr must be stloc"); + // ensure the variable is only accessed only a single time + if (method.GetSelfAndChildrenRecursive().Count(e => e != expr && e.Operand == expr.Operand) != 1) + return false; + ILExpression parent; + int pos; + if (FindLoadInNext(next as ILExpression, (ILVariable)expr.Operand, out parent, out pos) == true) { + parent.Arguments[pos] = expr.Arguments[0]; + return true; + } + return false; + } + + /// + /// Finds the position to inline to. + /// + /// true = found; false = cannot continue search; null = not found + static bool? FindLoadInNext(ILExpression expr, ILVariable v, out ILExpression parent, out int pos) + { + for (int i = 0; i < expr.Arguments.Count; i++) { + ILExpression arg = expr.Arguments[i]; + if (arg.Code == ILCode.Ldloc && arg.Operand == v) { + parent = expr; + pos = i; + return true; + } + bool? r = FindLoadInNext(arg, v, out parent, out pos); + if (r != null) + return r; + } + parent = null; + pos = 0; + return IsWithoutSideEffects(expr.Code) ? (bool?)null : false; + } + + static bool IsWithoutSideEffects(ILCode code) + { + return code == ILCode.Ldloc; + } + } +}