Sometimes I use IntPtr instead of Type as a key (or part of a complex key) in Dictionary.
Advantages is that it is a value type so I don't keep full blown Type object alive, and GC likes value type fields more than ref ones because less references to follow.
But each time I need to get the value or check if a key exists I have to get Type just to retrieve its handle value.
I suggest intrinsifying these calls:
``` C#
[obj.]GetType().TypeHandle.Value
typeof(T).TypeHandle.Value
### How
In the following code JIT just compares method table pointer in the object header to the address of method table of `String` type.
``` C#
[MethodImpl(MethodImplOptions.NoInlining)]
private static bool TestMtCheck(object obj)
{
return obj.GetType() == typeof(String);
}
mov rax,7FEF61BDA88h
cmp qword ptr [rcx],rax
sete al
movzx eax,al
ret
It could do the same with getting type handle value :
``` C#
[MethodImpl(MethodImplOptions.NoInlining)]
private static IntPtr TestGetHandle(object obj)
{
return obj.GetType().TypeHandle.Value;
}
MethodImpl(MethodImplOptions.NoInlining)]
private static IntPtr TestGetHandle()
{
return typeof(String).TypeHandle.Value;
}
``` ASM
mov rax, qword ptr [rcx]
ret
mov rax, 7FEF61BDA88h
ret
category:cq
theme:type-intrinsics
skill-level:expert
cost:medium
And I know about existence of collectible types :)
/cc @RussKeldorph
@jkotas Would JIT be involved in this one?
Yes, this would be JIT work.
There are complications with array type handles and proxy type handles (for remoting on full framework) - the type handle is not equal to methodtable for these.
It may be better to implement fixups for System.Type instead. It would avoid helper call to get to the System.Type. This optimization would be applicable more broadly, and it would make access to the raw handle value cheaper too. I have conversion about it with @cmckinsey @geoffkizer recently.
@jkotas did you ever do any writeup for the fixup idea?
Today, ldtoken is expanded to embedGenericHandle + CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE.
We can add a new method to JIT/EE interface bool expandLdToken(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_GENERICHANDLE_RESULT * pResult) that would allow short-circuiting this if possible. ldtoken would be the lookup returned by bool expandLdToken(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_GENERICHANDLE_RESULT * pResult) and we would save CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE call.
Yesterday I've been working on improving the performance of GC.AllocateUninitializedArray to be able to use it effectively in StringBuilder.
typeof(T[]).TypeHandle.Value (mind the array of T, not just T) used in the following line:
showed up in the profiles:

It was just a few %, which itself is not bad. The problem was that this generic code is executed only for value types and having this extra call(s) (.GetRuntimeType and Handle.get_Value) increases the method size and hence prevents from inlining.
I had two cases recently where I could use this. (managed StelemRef and GC.Allocate[Uninitialized]Array API)
I believe the issues with array type handles should not be a problem any more.
Most helpful comment
There are complications with array type handles and proxy type handles (for remoting on full framework) - the type handle is not equal to methodtable for these.
It may be better to implement fixups for System.Type instead. It would avoid helper call to get to the System.Type. This optimization would be applicable more broadly, and it would make access to the raw handle value cheaper too. I have conversion about it with @cmckinsey @geoffkizer recently.