15 KiB
Shared Generics Design
Author: Fadi Hanna - 2019
Introduction
Shared generics is a runtime+JIT feature aimed at reducing the amount of code the runtime generates for generic methods of various instantiations (supports methods on generic types and generic methods). The idea is that for certain instantiations, the generated code will almost be identical with the exception of a few instructions, so in order to reduce the memory footprint, and the amount of time we spend jitting these generic methods, the runtime will generate a single special canonical version of the code, which can be used by all compatible instantiations of the method.
Canonical Codegen and Generic Dictionaries
Consider the following C# code sample:
string Func<T>()
{
return typeof(List<T>).ToString();
}
Without shared generics, the code for instantiations like Func<object>
or Func<string>
would look identical except for one single instruction: the one that loads the correct TypeHandle of type List<T>
:
mov rcx, type handle of List<string> or List<object>
call ToString()
ret
With shared generics, the canonical code will not have any hard-coded versions of the type handle of List, but instead looks up the exact type handle either through a call to a runtime helper API, or by loading it up from the generic dictionary of the instantiation of Func that is executing. The code would look more like the following:
mov rcx, generic context // MethodDesc of Func<string> or Func<object>
mov rcx, [rcx + offset of InstantiatedMethodDesc::m_pPerInstInfo] // This is the generic dictionary
mov rcx, [rcx + dictionary slot containing type handle of List<T>]
call ToString()
ret
The generic context in this example is the InstantiatedMethodDesc of Func<object>
or Func<string>
. The generic dictionary is a data structure used by shared generic code to fetch instantiation-specific information. It is basically an array where the entries are instantiation-specific type handles, method handles, field handles, method entry points, etc... The "PerInstInfo" fields on MethodTable and InstantiatedMethodDesc structures point at the generic dictionary structure for a generic type and method respectively.
In this example, the generic dictionary for Func