Reputation: 4051
For example we have a multidimensional array of doubles
double[,] d = new double[1,2];
d.GetType()
returns {Name = "Double[,]" FullName = "System.Double[,]"}
d[0,0]
is compiled to call instance float64 float64[0..., 0...]::Get(int32, int32)
IL
How is the source code of type System.Double[,]
generated?
Is it baked in CLR or Roslyn is responsible for its generation?
Upvotes: 3
Views: 610
Reputation: 244777
Array types are handled in a special way by the CLR (both single-dimensional and multi-dimensional arrays and each in a different special way). For multi-dimensional arrays, all Roslyn does is to call
the Get()
method and the CLR takes care of the rest.
What exactly the CLR does is quite complicated (at least it seems that way to me), but I believe the most relevant part starts in Lowering::LowerArrElem
.
The end result is that a method like this one:
[MethodImpl(MethodImplOptions.NoInlining)]
private static double Get(double[,] d)
{
return d[0, 0];
}
compiles to the this x64 code (comments mine):
// stack pointer adjustment, not interesting
sub rsp,28h
// eax = 0
xor eax,eax
// range check first dimension against eax
sub eax,dword ptr [rcx+18h]
cmp eax,dword ptr [rcx+10h]
jae 00007FFD0A554521
// edx = 0
xor edx,edx
// range check second dimension against edx
sub edx,dword ptr [rcx+1Ch]
cmp edx,dword ptr [rcx+14h]
jae 00007FFD0A554521
// compute item offset
mov r8d,dword ptr [rcx+14h]
imul r8,rax
mov rax,rdx
add rax,r8
// load result into xmm0
movsd xmm0,mmword ptr [rcx+rax*8+20h]
// stack pointer adjustment, not interesting
add rsp,28h
// return
ret
Upvotes: 1
Reputation: 111860
What you are looking for is in the arraynative.cpp and arraynative.h.
Starting from Array.cs:
public unsafe Object GetValue(params int[] indices)
uses
fixed(int* pIndices = indices)
InternalGetReference(&elemref, indices.Length, pIndices);
Where InternalGetReference()
is (same file):
[MethodImplAttribute(MethodImplOptions.InternalCall)]
// reference to TypedReference is banned, so have to pass result as pointer
private unsafe extern void InternalGetReference(void * elemRef, int rank, int * pIndices);
The MethodImplOptions.InternalCall
are defined in ecalllist.h (remember this file... It contains all the MethodImplOptions.InternalCall
, so it is quite useful) (if you don't remember the name of the file, you can simply search for InternalGetReference
in the github... there aren't many files containing that word):
FCFuncElement("InternalGetReference", ArrayNative::GetReference)
So you have to look for ArrayNative
, that is in the two files I linked.
Upvotes: 6