Generics
Terminology
Type/Method instantiation == Type/Method instance == Inflated Type/Method.
Generic Type Definitions
These are represented by a normal MonoClass
structure with the generic_container
field set. This field points to a MonoGenericContainer
structure, which stores information about the generic parameters of the generic type.
Generic Type Instantiations
These are represented by a pair of MonoGenericClass
and MonoClass
structures. The generic_class
field in MonoClass is used to link the two together. The reason for the split is to avoid allocating a large MonoClass if not needed.
It would have been better to name MonoGenericClass
MonoInflatedClass
or something similar.
Generic Method Definitions
These are represented by a MonoMethod
structure with the is_generic
field set to 1.
Generic Method Instantiations
These are represented by a MonoMethodInflated
structure, which is an extension of the MonoMethod
structure. Its is_inflated
field is set to 1.
One consequence of this design is that a method cannot be a pinvoke method/wrapper/dynamic method and an inflated method at the same time.
MonoGenericContext
This structure holds information of an instantiation of a set of generic parameters with generic arguments. It is used by both type and method instatiations.
Canonical generic instances
The runtime canonizes generic type/method instances, so for every set of generic arguments, there is only one type/method instance with those arguments. This is using caches in metadata.c
.
Lifetime of inflated types/methods
Inflated types and methods depend on the assembly of the generic type/method definition they are inflated from, along with the assemblies of their generic arguments. This is handled using the concept of ‘image sets’ in metadata.c. Every inflated type/method belongs to an image set, which is a set of MonoImages. When one of the assemblies in an image set is unloaded, all the inflated types/methods belonging to the image set are freed. Memory for inflated types/methods cannot be allocated from mempools, it is allocated from the heap. The mono_class_alloc/alloc0
functions can be used to allocate memory from the appropriate place.
System.Reflection.Emit
Generics support in System.Reflection.Emit (SRE) is very problematic because it is possible to create generic instances of not yet created dynamic types, i.e. if T is a generic TypeBuilder, it is possible to create T<int>. The latter is not a TypeBuilder any more, but a normal Type, which presents several problems:
- this type needs to be kept in sync with the original TypeBuilder, i.e. if methods/fields are added to the TypeBuilder, this should be reflected in the instantiation.
- this type cannot be used normally until its TypeBuilder is finished, ie. its not possible to create instances of it etc.
These problems are currently handled by a hierarchy of C# classes which inherit from the normal reflection classes:
MonoGenericClass
represents an instantiation of a generic TypeBuilder. MS.NET calls thisTypeBuilderInstantiation
, a much better name.Method/Field/Event/PropertyOnTypeBuilderInst
represents a method/field etc. of aMonoGenericClass
.