Browse Source

Reduce allocations in TransformArrayInitializers

DecodeArrayInitializer - Instead of relying on the Add method of a list to expand the underlying array when necessary, the code now allocates a big enough array to fit all the elements removing the need for the Add method to expand the array several times.

BlockFromInitializer now reuses a single instance of List<ILInstruction> instead of reallocating a new one every time and clears it when necessary. The same pre-allocation approach mentioned above has been implemented here too.
pull/2731/head
ElektroKill 3 years ago
parent
commit
760a6a653e
No known key found for this signature in database
GPG Key ID: 7E3C5C084E40E3EC
  1. 11
      ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs
  2. 25
      ICSharpCode.Decompiler/Util/CollectionExtensions.cs

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

@ -1,4 +1,4 @@
// Copyright (c) 2015 Siegfried Pammer // Copyright (c) 2015 Siegfried Pammer
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software // software and associated documentation files (the "Software"), to deal in the Software
@ -620,16 +620,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var block = new Block(BlockKind.ArrayInitializer); var block = new Block(BlockKind.ArrayInitializer);
block.Instructions.Add(new StLoc(v, new NewArr(elementType, arrayLength.Select(l => new LdcI4(l)).ToArray()))); block.Instructions.Add(new StLoc(v, new NewArr(elementType, arrayLength.Select(l => new LdcI4(l)).ToArray())));
int step = arrayLength.Length + 1; int step = arrayLength.Length + 1;
var indices = new List<ILInstruction>();
for (int i = 0; i < values.Length / step; i++) for (int i = 0; i < values.Length / step; i++)
{ {
// values array is filled backwards // values array is filled backwards
var value = values[step * i]; var value = values[step * i];
var indices = new List<ILInstruction>();
indices.EnsureCapacity(step - 1);
for (int j = step - 1; j >= 1; j--) for (int j = step - 1; j >= 1; j--)
{ {
indices.Add(values[step * i + j]); indices.Add(values[step * i + j]);
} }
block.Instructions.Add(StElem(new LdLoc(v), indices.ToArray(), value, elementType)); block.Instructions.Add(StElem(new LdLoc(v), indices.ToArray(), value, elementType));
indices.Clear();
} }
block.FinalInstruction = new LdLoc(v); block.FinalInstruction = new LdLoc(v);
return block; return block;
@ -774,6 +779,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (initialValue.RemainingBytes < (totalLength * elementSize)) if (initialValue.RemainingBytes < (totalLength * elementSize))
return false; return false;
output.EnsureCapacity(totalLength + totalLength * arrayLength.Length);
for (int i = 0; i < totalLength; i++) for (int i = 0; i < totalLength; i++)
{ {
output.Add(decoder(ref initialValue)); output.Add(decoder(ref initialValue));

25
ICSharpCode.Decompiler/Util/CollectionExtensions.cs

@ -371,6 +371,31 @@ namespace ICSharpCode.Decompiler.Util
return first; return first;
} }
#if !NETCORE
public static int EnsureCapacity<T>(this List<T> list, int capacity)
{
if (capacity < 0)
throw new ArgumentOutOfRangeException(nameof(capacity));
if (list.Capacity < capacity)
{
const int DefaultCapacity = 4;
const int MaxLength = 0X7FFFFFC7;
int newcapacity = list.Capacity == 0 ? DefaultCapacity : 2 * list.Capacity;
if ((uint)newcapacity > MaxLength)
newcapacity = MaxLength;
if (newcapacity < capacity)
newcapacity = capacity;
list.Capacity = newcapacity;
}
return list.Capacity;
}
#endif
#region Aliases/shortcuts for Enumerable extension methods #region Aliases/shortcuts for Enumerable extension methods
public static bool Any<T>(this ICollection<T> list) => list.Count > 0; public static bool Any<T>(this ICollection<T> list) => list.Count > 0;
public static bool Any<T>(this T[] array, Predicate<T> match) => Array.Exists(array, match); public static bool Any<T>(this T[] array, Predicate<T> match) => Array.Exists(array, match);

Loading…
Cancel
Save