Browse Source

Detect simple array initializers as well

pull/734/head
Siegfried Pammer 9 years ago
parent
commit
e790646244
  1. 29
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  2. 52
      ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs
  3. 11
      ICSharpCode.Decompiler/Util/CollectionExtensions.cs

29
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -22,6 +22,7 @@ using System.Threading; @@ -22,6 +22,7 @@ using System.Threading;
using ICSharpCode.NRefactory.TypeSystem;
using Mono.Cecil;
using ICSharpCode.Decompiler.Disassembler;
using System.Linq;
namespace ICSharpCode.Decompiler.IL
{
@ -86,6 +87,34 @@ namespace ICSharpCode.Decompiler.IL @@ -86,6 +87,34 @@ namespace ICSharpCode.Decompiler.IL
}
}
public ILVariable RegisterVariable(VariableKind kind, IType type, string name = null)
{
int index = Variables.Where(v => v.Kind == kind).MaxOrDefault(v => v.Index, -1) + 1;
if (string.IsNullOrWhiteSpace(name)) {
switch (kind) {
case VariableKind.Local:
name = "V_";
break;
case VariableKind.Parameter:
name = "P_";
break;
case VariableKind.Exception:
name = "E_";
break;
case VariableKind.StackSlot:
name = "S_";
break;
default:
throw new NotSupportedException();
}
name += index;
}
var variable = new ILVariable(kind, type, index);
variable.Name = name;
Variables.Add(variable);
return variable;
}
public static ILFunction Read(IDecompilerTypeSystem context, IMethod method, CancellationToken cancellationToken = default(CancellationToken))
{
return Read(context, (MethodDefinition)context.GetCecil(method), cancellationToken);

52
ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

@ -24,13 +24,19 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation; @@ -24,13 +24,19 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler.IL.Transforms
{
/// <summary>
/// Transforms array initialization pattern of System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray.
/// For collection and object initializers see <see cref="TransformInitializers"/>
/// </summary>
public class TransformArrayInitializers : IILTransform
{
ILTransformContext context;
ILFunction function;
void IILTransform.Run(ILFunction function, ILTransformContext context)
{
this.context = context;
this.function = function;
foreach (var block in function.Descendants.OfType<Block>()) {
for (int i = block.Instructions.Count - 1; i >= 0; i--) {
if (!DoTransform(block, i))
@ -52,12 +58,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -52,12 +58,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILInstruction[] values;
int initArrayPos;
if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out values, out initArrayPos)) {
var block = BlockFromInitializer(v, elementType, arrayLength, values);
var tempStore = function.RegisterVariable(VariableKind.StackSlot, v.Type);
var block = BlockFromInitializer(tempStore, elementType, arrayLength, values);
body.Instructions[pos].ReplaceWith(new StLoc(v, block));
body.Instructions.RemoveAt(initArrayPos);
new ILInlining().InlineIfPossible(body, ref pos);
return true;
}
ILVariable finalStore;
if (arrayLength.Length == 1 && HandleSimpleArrayInitializer(body, pos + 1, v, elementType, arrayLength[0], out finalStore, out values)) {
var block = new Block();
var tempStore = function.RegisterVariable(VariableKind.StackSlot, v.Type);
block.Instructions.Add(new StLoc(tempStore, new NewArr(elementType, arrayLength.Select(l => new LdcI4(l)).ToArray())));
block.Instructions.AddRange(values.SelectWithIndex((i, value) => StElem(new LdLoc(tempStore), new[] { new LdcI4(i) }, value.Clone(), elementType)));
block.FinalInstruction = new LdLoc(tempStore);
body.Instructions[pos].ReplaceWith(new StLoc(finalStore, block));
for (int n = 0; n <= values.Length; n++)
body.Instructions.RemoveAt(pos + 1);
//body.Instructions.RemoveRange(pos + 1, values.Length + 1);
new ILInlining().InlineIfPossible(body, ref pos);
return true;
}
// Put in a limit so that we don't consume too much memory if the code allocates a huge array
// and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler!
// const int maxConsecutiveDefaultValueExpressions = 300;
@ -87,6 +108,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -87,6 +108,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
}
/// <summary>
/// Handle simple case where RuntimeHelpers.InitializeArray is not used.
/// </summary>
bool HandleSimpleArrayInitializer(Block block, int pos, ILVariable store, IType elementType, int length, out ILVariable finalStore, out ILInstruction[] values)
{
values = null;
finalStore = null;
if (pos + length >= block.Instructions.Count)
return false;
values = new ILInstruction[length];
for (int i = pos; i < block.Instructions.Count; i++) {
ILInstruction target, value;
IType type;
int offset = i - pos;
if (offset >= length)
break;
if (!block.Instructions[i].MatchStObj(out target, out value, out type) || !elementType.Equals(type))
return false;
var ldelem = target as LdElema;
if (ldelem == null || !ldelem.Array.MatchLdLoc(store) || ldelem.Indices.Count != 1 || !ldelem.Indices[0].MatchLdcI4(offset))
return false;
values[offset] = value;
}
ILInstruction array;
return block.Instructions[pos + length].MatchStLoc(out finalStore, out array) && array.MatchLdLoc(store);
}
bool DoTransformMultiDim(Block body, int pos)
{
if (pos >= body.Instructions.Count - 2)
@ -146,7 +194,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -146,7 +194,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
bool MatchNewArr(ILInstruction instruction, out IType arrayType, out int[] length)
internal static bool MatchNewArr(ILInstruction instruction, out IType arrayType, out int[] length)
{
NewArr newArr = instruction as NewArr;
length = null;

11
ICSharpCode.Decompiler/Util/CollectionExtensions.cs

@ -27,9 +27,9 @@ namespace ICSharpCode.Decompiler @@ -27,9 +27,9 @@ namespace ICSharpCode.Decompiler
return stack.Peek();
}
public static int MaxOrDefault<T>(this IEnumerable<T> input, Func<T, int> selector)
public static int MaxOrDefault<T>(this IEnumerable<T> input, Func<T, int> selector, int defaultValue = 0)
{
int max = 0;
int max = defaultValue;
foreach (var element in input) {
int value = selector(element);
if (value > max)
@ -58,6 +58,13 @@ namespace ICSharpCode.Decompiler @@ -58,6 +58,13 @@ namespace ICSharpCode.Decompiler
return result;
}
public static IEnumerable<U> SelectWithIndex<T, U>(this IEnumerable<T> source, Func<int, T, U> func)
{
int index = 0;
foreach (var element in source)
yield return func(index++, element);
}
/// <summary>
/// The merge step of merge sort.
/// </summary>

Loading…
Cancel
Save