--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace ILCompiler.Sorting.Implementation
+{
+ internal struct ArrayAccessor<T> : ISortableDataStructureAccessor<T, T[]>
+ {
+ public void Copy(T[] source, int sourceIndex, T[] target, int destIndex, int length)
+ {
+ Array.Copy(source, sourceIndex, target, destIndex, length);
+ }
+
+ public T GetElement(T[] dataStructure, int i)
+ {
+ return dataStructure[i];
+ }
+
+ public int GetLength(T[] dataStructure)
+ {
+ return dataStructure.Length;
+ }
+
+ public void SetElement(T[] dataStructure, int i, T value)
+ {
+ dataStructure[i] = value;
+ }
+
+ public void SwapElements(T[] dataStructure, int i, int i2)
+ {
+ T temp = dataStructure[i];
+ dataStructure[i] = dataStructure[i + 1];
+ dataStructure[i + 1] = temp;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+
+namespace ILCompiler
+{
+ internal interface ICompareAsEqualAction
+ {
+ void CompareAsEqual();
+ }
+
+ internal struct RequireTotalOrderAssert : ICompareAsEqualAction
+ {
+ public void CompareAsEqual()
+ {
+ Debug.Assert(false);
+ }
+ }
+
+ internal struct AllowDuplicates : ICompareAsEqualAction
+ {
+ public void CompareAsEqual()
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace ILCompiler
+{
+ internal interface ISortableDataStructureAccessor<T, TDataStructure>
+ {
+ T GetElement(TDataStructure dataStructure, int i);
+ void SetElement(TDataStructure dataStructure, int i, T value);
+ void SwapElements(TDataStructure dataStructure, int i, int i2);
+ void Copy(TDataStructure source, int sourceIndex, T[] target, int destIndex, int length);
+ void Copy(T[] source, int sourceIndex, TDataStructure target, int destIndex, int length);
+ int GetLength(TDataStructure dataStructure);
+ }
+}
\ No newline at end of file
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+
+namespace ILCompiler.Sorting.Implementation
+{
+ internal struct ListAccessor<T> : ISortableDataStructureAccessor<T, List<T>>
+ {
+ public void Copy(List<T> source, int sourceIndex, T[] target, int destIndex, int length)
+ {
+ source.CopyTo(sourceIndex, target, destIndex, length);
+ }
+
+ public void Copy(T[] source, int sourceIndex, List<T> target, int destIndex, int length)
+ {
+ for (int i = 0; i < length; i++)
+ {
+ target[i + destIndex] = source[i + sourceIndex];
+ }
+ }
+
+ public T GetElement(List<T> dataStructure, int i)
+ {
+ return dataStructure[i];
+ }
+
+ public int GetLength(List<T> dataStructure)
+ {
+ return dataStructure.Count;
+ }
+
+ public void SetElement(List<T> dataStructure, int i, T value)
+ {
+ dataStructure[i] = value;
+ }
+
+ public void SwapElements(List<T> dataStructure, int i, int i2)
+ {
+ T temp = dataStructure[i];
+ dataStructure[i] = dataStructure[i + 1];
+ dataStructure[i + 1] = temp;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using ILCompiler.Sorting.Implementation;
+
+namespace ILCompiler
+{
+ public static class MergeSortApi
+ {
+ // Parallel sorting api which will sort in parallel when appropriate
+ public static void MergeSort<T>(this List<T> listToSort, Comparison<T> comparison)
+ {
+ MergeSortCore<T, List<T>, ListAccessor<T>, ComparisonWrapper<T>, RequireTotalOrderAssert>.ParallelSortApi(listToSort, new ComparisonWrapper<T>(comparison));
+ }
+
+ // Parallel sorting api which will sort in parallel when appropriate
+ public static void MergeSortAllowDuplicates<T>(this List<T> listToSort, Comparison<T> comparison)
+ {
+ MergeSortCore<T, List<T>, ListAccessor<T>, ComparisonWrapper<T>, AllowDuplicates>.ParallelSortApi(listToSort, new ComparisonWrapper<T>(comparison));
+ }
+
+ // Parallel sorting api which will sort in parallel when appropriate
+ public static void MergeSort<T>(this List<T> listToSort, IComparer<T> comparer)
+ {
+ MergeSortCore<T, List<T>, ListAccessor<T>, IComparer<T>, RequireTotalOrderAssert>.ParallelSortApi(listToSort, comparer);
+ }
+
+ // Parallel sorting api which will sort in parallel when appropriate
+ public static void MergeSortAllowDuplicates<T>(this List<T> listToSort, IComparer<T> comparer)
+ {
+ MergeSortCore<T, List<T>, ListAccessor<T>, IComparer<T>, AllowDuplicates>.ParallelSortApi(listToSort, comparer);
+ }
+
+ // Parallel sorting api which will sort in parallel when appropriate
+ public static void MergeSort<T>(this T[] arrayToSort, Comparison<T> comparison)
+ {
+ MergeSortCore<T, T[], ArrayAccessor<T>, ComparisonWrapper<T>, RequireTotalOrderAssert>.ParallelSortApi(arrayToSort, new ComparisonWrapper<T>(comparison));
+ }
+
+ // Parallel sorting api which will sort in parallel when appropriate
+ public static void MergeSortAllowDuplicates<T>(this T[] arrayToSort, Comparison<T> comparison)
+ {
+ MergeSortCore<T, T[], ArrayAccessor<T>, ComparisonWrapper<T>, AllowDuplicates>.ParallelSortApi(arrayToSort, new ComparisonWrapper<T>(comparison));
+ }
+
+ // Parallel sorting api which will sort in parallel when appropriate
+ public static void MergeSort<T>(this T[] arrayToSort, IComparer<T> comparer)
+ {
+ MergeSortCore<T, T[], ArrayAccessor<T>, IComparer<T>, RequireTotalOrderAssert>.ParallelSortApi(arrayToSort, comparer);
+ }
+
+ // Parallel sorting api which will sort in parallel when appropriate
+ public static void MergeSortAllowDuplicates<T>(this T[] arrayToSort, IComparer<T> comparer)
+ {
+ MergeSortCore<T, T[], ArrayAccessor<T>, IComparer<T>, AllowDuplicates>.ParallelSortApi(arrayToSort, comparer);
+ }
+
+
+ // Internal helper struct used to enable use of Comparison<T> delegates instead of IComparer<T> instances
+ private struct ComparisonWrapper<T> : IComparer<T>
+ {
+ Comparison<T> _comparison;
+ public ComparisonWrapper(Comparison<T> comparison)
+ {
+ _comparison = comparison;
+ }
+ int IComparer<T>.Compare(T x, T y)
+ {
+ return _comparison(x, y);
+ }
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace ILCompiler.Sorting.Implementation
+{
+ internal static class MergeSortCore<T, TDataStructure, TDataStructureAccessor, TComparer, TCompareAsEqualAction>
+ where TDataStructureAccessor:ISortableDataStructureAccessor<T, TDataStructure>
+ where TComparer:IComparer<T>
+ where TCompareAsEqualAction : ICompareAsEqualAction
+ {
+ internal const int ParallelSortThreshold = 4000; // Number empirically measured by compiling
+ // a large composite binary
+
+ public static void ParallelSortApi(TDataStructure arrayToSort, TComparer comparer)
+ {
+ TDataStructureAccessor accessor = default(TDataStructureAccessor);
+ if (accessor.GetLength(arrayToSort) < ParallelSortThreshold)
+ {
+ // If the array is sufficiently small as to not need parallel sorting
+ // call the sequential algorithm directly, as the parallel api will create
+ // an unnecessary Task object to wait on
+ SequentialSort(arrayToSort, 0, accessor.GetLength(arrayToSort), comparer);
+ }
+ ParallelSort(arrayToSort, 0, accessor.GetLength(arrayToSort), comparer).Wait();
+ }
+
+ // Parallelized merge sort algorithm. Uses Task infrastructure to spread sort across available resources
+ private static async Task ParallelSort(TDataStructure arrayToSort, int index, int length, TComparer comparer)
+ {
+ if (length < ParallelSortThreshold)
+ {
+ SequentialSort(arrayToSort, index, length, comparer);
+ }
+ else
+ {
+ TDataStructureAccessor accessor = default(TDataStructureAccessor);
+ int halfLen = length / 2;
+
+ TaskCompletionSource<bool> rightSortComplete = new System.Threading.Tasks.TaskCompletionSource<bool>();
+ _ = Task.Run(async () =>
+ {
+ await ParallelSort(arrayToSort, index + halfLen, length - halfLen, comparer);
+ rightSortComplete.SetResult(true);
+ });
+
+ T[] localCopyOfHalfOfArray = new T[halfLen];
+ accessor.Copy(arrayToSort, index, localCopyOfHalfOfArray, 0, halfLen);
+ await MergeSortCore<T, T[], ArrayAccessor<T>, TComparer, TCompareAsEqualAction>.ParallelSort(localCopyOfHalfOfArray, 0, halfLen, comparer);
+ await rightSortComplete.Task;
+ Merge(localCopyOfHalfOfArray, arrayToSort, index, halfLen, length, comparer);
+ }
+ }
+
+ // Normal non-parallel merge sort
+ // Allocates length/2 in scratch space
+ private static void SequentialSort(TDataStructure arrayToSort, int index, int length, TComparer comparer)
+ {
+ TDataStructureAccessor accessor = default(TDataStructureAccessor);
+ T[] scratchSpace = new T[accessor.GetLength(arrayToSort) / 2];
+ MergeSortHelper(arrayToSort, index, length, comparer, scratchSpace);
+ }
+
+ // Non-parallel merge sort, used once the region to be sorted is small enough
+ // scratchSpace must be at least length/2 in size
+ private static void MergeSortHelper(TDataStructure arrayToSort, int index, int length, TComparer comparer, T[] scratchSpace)
+ {
+ if (length <= 1)
+ {
+ return;
+ }
+ TDataStructureAccessor accessor = default(TDataStructureAccessor);
+ if (length == 2)
+ {
+ if (comparer.Compare(accessor.GetElement(arrayToSort, index), accessor.GetElement(arrayToSort, index + 1)) > 0)
+ {
+ accessor.SwapElements(arrayToSort, index, index + 1);
+ }
+ return;
+ }
+
+ int halfLen = length / 2;
+ MergeSortHelper(arrayToSort, index, halfLen, comparer, scratchSpace);
+ MergeSortHelper(arrayToSort, index + halfLen, length - halfLen, comparer, scratchSpace);
+ accessor.Copy(arrayToSort, index, scratchSpace, 0, halfLen);
+ Merge(scratchSpace, arrayToSort, index, halfLen, length, comparer);
+ }
+
+ // Shared merge algorithm used in both parallel and sequential variants of the mergesort
+ private static void Merge(T[] localCopyOfHalfOfArray, TDataStructure arrayToSort, int index, int halfLen, int length, TComparer comparer)
+ {
+ TDataStructureAccessor accessor = default(TDataStructureAccessor);
+ int leftHalfIndex = 0;
+ int rightHalfIndex = index + halfLen;
+ int rightHalfEnd = index + length;
+ for (int i = 0; i < length; i++)
+ {
+ if (leftHalfIndex == halfLen)
+ {
+ // All of the remaining elements must be from the right half, and thus must already be in position
+ break;
+ }
+ if (rightHalfIndex == rightHalfEnd)
+ {
+ // Copy remaining elements from the local copy
+ accessor.Copy(localCopyOfHalfOfArray, leftHalfIndex, arrayToSort, index + i, length - i);
+ break;
+ }
+
+ int comparisonResult = comparer.Compare(localCopyOfHalfOfArray[leftHalfIndex], accessor.GetElement(arrayToSort, rightHalfIndex));
+ if (comparisonResult == 0)
+ {
+ default(TCompareAsEqualAction).CompareAsEqual();
+ }
+ if (comparisonResult <= 0)
+ {
+ accessor.SetElement(arrayToSort, i + index, localCopyOfHalfOfArray[leftHalfIndex++]);
+ }
+ else
+ {
+ accessor.SetElement(arrayToSort, i + index, accessor.GetElement(arrayToSort, rightHalfIndex++));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
} while (_markStack.Count != 0);
if (_resultSorter != null)
- _markedNodes.Sort(_resultSorter);
+ _markedNodes.MergeSortAllowDuplicates(_resultSorter);
_markedNodesFinal = _markedNodes.ToImmutableArray();
_markedNodes = null;
<Compile Include="IDependencyNode.cs" />
<Compile Include="NoLogStrategy.cs" />
<Compile Include="PerfEventSource.cs" />
+ <Compile Include="..\..\Common\Sorting\ArrayAccessor.cs">
+ <Link>Sorting\ArrayAccessor.cs</Link>
+ </Compile>
+ <Compile Include="..\..\Common\Sorting\ICompareAsEqualAction.cs">
+ <Link>Sorting\ICompareAsEqualAction.cs</Link>
+ </Compile>
+ <Compile Include="..\..\Common\Sorting\ISortableDataStructureAccessor.cs">
+ <Link>Sorting\ISortableDataStructureAccessor.cs</Link>
+ </Compile>
+ <Compile Include="..\..\Common\Sorting\ListAccessor.cs">
+ <Link>Sorting\ListAccessor.cs</Link>
+ </Compile>
+ <Compile Include="..\..\Common\Sorting\MergeSort.cs">
+ <Link>Sorting\MergeSort.cs</Link>
+ </Compile>
+ <Compile Include="..\..\Common\Sorting\MergeSortCore.cs">
+ <Link>Sorting\MergeSortCore.cs</Link>
+ </Compile>
+
</ItemGroup>
</Project>
builder.RequireInitialPointerAlignment();
if (_sorter != null)
- _nestedNodesList.Sort(_sorter);
+ _nestedNodesList.MergeSort(_sorter);
builder.AddSymbol(StartSymbol);
definedSymbols: new ISymbolDefinitionNode[] { this });
}
- _methods.Sort(new CompilerComparer());
+ _methods.MergeSort(new CompilerComparer());
GCRefMapBuilder builder = new GCRefMapBuilder(factory.Target, relocsOnly);
builder.Builder.RequireInitialAlignment(4);
builder.Builder.AddSymbol(this);
// Don't bother sorting if we're not emitting the contents
if (!relocsOnly)
- _items.Sort((x, y) => Comparer<int>.Default.Compare((int)x.Id, (int)y.Id));
+ _items.MergeSort((x, y) => Comparer<int>.Default.Compare((int)x.Id, (int)y.Id));
// ReadyToRunHeader.Flags
builder.EmitInt((int)_flags);
}
List<EcmaMethod> sortedInliners = new List<EcmaMethod>(inlineeWithInliners.Value);
- sortedInliners.Sort((a, b) =>
+ sortedInliners.MergeSort((a, b) =>
{
if (a == b)
return 0;
return null;
}
- fixupCells.Sort(FixupCell.Comparer);
+ fixupCells.MergeSortAllowDuplicates(FixupCell.Comparer);
// Deduplicate fixupCells
int j = 0;
foreach (var perModuleData in perModuleDatas)
{
- perModuleData.MethodsGenerated.Sort(sortHelper);
- perModuleData.GenericMethodsGenerated.Sort(sortHelper);
+ perModuleData.MethodsGenerated.MergeSort(sortHelper);
+ perModuleData.GenericMethodsGenerated.MergeSort(sortHelper);
_completeSortedMethods.AddRange(perModuleData.MethodsGenerated);
_completeSortedMethods.AddRange(perModuleData.GenericMethodsGenerated);
_completeSortedGenericMethods.AddRange(perModuleData.GenericMethodsGenerated);
}
- _completeSortedMethods.Sort(sortHelper);
- _completeSortedGenericMethods.Sort(sortHelper);
+ _completeSortedMethods.MergeSort(sortHelper);
+ _completeSortedGenericMethods.MergeSort(sortHelper);
_sortedMethods = true;
}
}
/// <param name="location">RVA and file location of the .edata section</param>
private BlobBuilder SerializeExportSection(SectionLocation sectionLocation)
{
- _exportSymbols.Sort((es1, es2) => StringComparer.Ordinal.Compare(es1.Name, es2.Name));
+ _exportSymbols.MergeSort((es1, es2) => StringComparer.Ordinal.Compare(es1.Name, es2.Name));
BlobBuilder builder = new BlobBuilder();