From 760a6a653e4d7e30001568dbc7201c25ec3cfb78 Mon Sep 17 00:00:00 2001 From: ElektroKill Date: Fri, 1 Jul 2022 18:45:46 +0200 Subject: [PATCH] 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 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. --- .../Transforms/TransformArrayInitializers.cs | 11 ++++++-- .../Util/CollectionExtensions.cs | 25 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs index 10cabcdea..3bb5cc797 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs +++ b/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 // 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); block.Instructions.Add(new StLoc(v, new NewArr(elementType, arrayLength.Select(l => new LdcI4(l)).ToArray()))); int step = arrayLength.Length + 1; + + var indices = new List(); for (int i = 0; i < values.Length / step; i++) { // values array is filled backwards var value = values[step * i]; - var indices = new List(); + + indices.EnsureCapacity(step - 1); for (int j = step - 1; j >= 1; j--) { indices.Add(values[step * i + j]); } + block.Instructions.Add(StElem(new LdLoc(v), indices.ToArray(), value, elementType)); + indices.Clear(); } block.FinalInstruction = new LdLoc(v); return block; @@ -774,6 +779,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (initialValue.RemainingBytes < (totalLength * elementSize)) return false; + output.EnsureCapacity(totalLength + totalLength * arrayLength.Length); + for (int i = 0; i < totalLength; i++) { output.Add(decoder(ref initialValue)); diff --git a/ICSharpCode.Decompiler/Util/CollectionExtensions.cs b/ICSharpCode.Decompiler/Util/CollectionExtensions.cs index e847c0bca..11be785b9 100644 --- a/ICSharpCode.Decompiler/Util/CollectionExtensions.cs +++ b/ICSharpCode.Decompiler/Util/CollectionExtensions.cs @@ -371,6 +371,31 @@ namespace ICSharpCode.Decompiler.Util return first; } +#if !NETCORE + public static int EnsureCapacity(this List 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 public static bool Any(this ICollection list) => list.Count > 0; public static bool Any(this T[] array, Predicate match) => Array.Exists(array, match);