Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What the interest of copying the reference of a field in a method body to read it while the field is never reassigned?

Tags:

c#

.net

.net-core

I was looking at the Dictionary<TKey, TValue> code in .NET Core and I've notice a kind of coding pattern also used in some builtin datastructures like Queue<T> or Stack<T> and List<T>.

For example about the : https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs#L482

We have:

Entry[] entries = _entries;
IEqualityComparer<TKey> comparer = _comparer;

I am not really sure why we keep a variable of the reference of the comparer and the entries, to me it's still referencing the same field.

It's not like the field is reassigned at some point if the same method body.

What is the interest of copying the reference if it's not reassigned, if there is some optimizations done by the compiler which would avoid this.field traversal?

like image 506
Natalie Perret Avatar asked Dec 28 '18 00:12

Natalie Perret


1 Answers

It looks like it is probably a hand-optimization, either for speed, or for smaller code size, or both.

Dereferencing a local variable is cheaper in terms of clock cycles than dereferencing a member variable, (which means that the C# compiler and JITter are not nearly as smart as I had hoped them to be,) and it is also more compact in terms of IL code length.

A local variable can usually be accessed with one IL instruction, and after JITting it can also usually be accessed with just one machine code instruction.

A member variable needs more work. At the IL level, we must specify that we want to access the this pointer, and that we want to access something at an offset from it, and we must specify the field identifying the member variable. After JITting, it depends how smart the JITter is, in theory it could be done in one instruction if the JITter can guarantee that a certain register always contains the address of this, but such a guarantee is hard to be had, so what is probably happening is that it takes one instruction to load this into a register and one more instruction to access the field at an offset from that register.

It is never worth coding like that when writing application code. But when writing a library that is used by huge numbers of people all over the planet around the clock, it makes sense to write the code so as to squeeze clock cycles here and there.

like image 166
Mike Nakis Avatar answered Oct 31 '22 12:10

Mike Nakis