Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Improve Dictionary TryGetValue size/perfomance (dotnet/coreclr#27195)
Browse files Browse the repository at this point in the history
* Dictionary avoid second bounds check in Get methods

* Add NullRef methods to Unsafe

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
  • Loading branch information
benaadams authored and safern committed Oct 21, 2019
1 parent 713f2d9 commit e8c4f71
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 72 deletions.
35 changes: 35 additions & 0 deletions src/Common/src/CoreLib/Internal/Runtime/CompilerServices/Unsafe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -387,5 +387,40 @@ public static IntPtr ByteOffset<T>(ref T origin, ref T target)
{
throw new PlatformNotSupportedException();
}

/// <summary>
/// Returns a by-ref to type <typeparamref name="T"/> that is a null reference.
/// </summary>
[Intrinsic]
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T NullRef<T>()
{
return ref Unsafe.AsRef<T>(null);

// ldc.i4.0
// conv.u
// ret
}

/// <summary>
/// Returns if a given by-ref to type <typeparamref name="T"/> is a null reference.
/// </summary>
/// <remarks>
/// This check is conceptually similar to "(void*)(&amp;source) == nullptr".
/// </remarks>
[Intrinsic]
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNullRef<T>(ref T source)
{
return Unsafe.AsPointer(ref source) == null;

// ldarg.0
// ldc.i4.0
// conv.u
// ceq
// ret
}
}
}
169 changes: 104 additions & 65 deletions src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/Common/src/CoreLib/System/Collections/HashHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace System.Collections
{
internal static partial class HashHelpers
{
public const int HashCollisionThreshold = 100;
public const uint HashCollisionThreshold = 100;

// This is the maximum prime smaller than Array.MaxArrayLength
public const int MaxPrimeArrayLength = 0x7FEFFFFD;
Expand Down
2 changes: 1 addition & 1 deletion src/Common/src/CoreLib/System/Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ public unsafe Span<T> Span
// in which case that's the dangerous operation performed by the dev, and we're just following
// suit here to make it work as best as possible.

ref T refToReturn = ref Unsafe.AsRef<T>(null);
ref T refToReturn = ref Unsafe.NullRef<T>();
int lengthOfUnderlyingSpan = 0;

// Copy this field into a local so that it can't change out from under us mid-operation.
Expand Down
2 changes: 1 addition & 1 deletion src/Common/src/CoreLib/System/ReadOnlyMemory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public unsafe ReadOnlySpan<T> Span
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ref T refToReturn = ref Unsafe.AsRef<T>(null);
ref T refToReturn = ref Unsafe.NullRef<T>();
int lengthOfUnderlyingSpan = 0;

// Copy this field into a local so that it can't change out from under us mid-operation.
Expand Down
4 changes: 2 additions & 2 deletions src/Common/src/CoreLib/System/ReadOnlySpan.Fast.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ public ref readonly T this[int index]
/// It can be used for pinning and is required to support the use of span within a fixed statement.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public unsafe ref readonly T GetPinnableReference()
public ref readonly T GetPinnableReference()
{
// Ensure that the native code has just one forward branch that is predicted-not-taken.
ref T ret = ref Unsafe.AsRef<T>(null);
ref T ret = ref Unsafe.NullRef<T>();
if (_length != 0) ret = ref _pointer.Value;
return ref ret;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Common/src/CoreLib/System/Span.Fast.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ public ref T this[int index]
/// It can be used for pinning and is required to support the use of span within a fixed statement.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public unsafe ref T GetPinnableReference()
public ref T GetPinnableReference()
{
// Ensure that the native code has just one forward branch that is predicted-not-taken.
ref T ret = ref Unsafe.AsRef<T>(null);
ref T ret = ref Unsafe.NullRef<T>();
if (_length != 0) ret = ref _pointer.Value;
return ref ret;
}
Expand Down

2 comments on commit e8c4f71

@nxtn
Copy link
Contributor

@nxtn nxtn commented on e8c4f71 Oct 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jkotas Do you want to add the NullRef methods to the public Unsafe class?

@jkotas
Copy link
Member

@jkotas jkotas commented on e8c4f71 Oct 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they need to be approved as public APIs first: https://github.com/dotnet/corefx/issues/41783

Please sign in to comment.