All of my posts on sharing generic code so far have been about sharing non-generic methods of generic classes, like this one:
class Gen<T> {
public T [] newArr (int n) {
return new T [n];
}
}
But what about generic methods, like this one:
class Gen<S> {
public Dictionary<S,T> newDict<T> () {
return new Dictionary<S,T> ();
}
}
If we want to share this methods between different instantiations, i.e. different type values of T, we need to provide a place for the code to look up the type of Dictionary<S,T>. This place cannot be the runtime generic context, because the data in there only depends on the type arguments of the class, i.e. S, but not of generic methods.
Our solution is to introduce a data structure very similar to the runtime generic context, called the method runtime generic context, or MRGCTX. It is associated not with generic classes and their type arguments, like the RGCTX, but with generic methods and their type arguments. We use the same MRGCTX for generic methods of a specific class if the method type arguments are the same. As an example, these methods would all share the same MRGCTX:
Gen<object>.foo<object,string> ()
Gen<object>.bar<object,string> ()
Gen<object>.quux<object,string> ()
while no two of these methods would use the same MRGCTX:
Gen<object>.foo<object,string> ()
Gen<object>.foo<string,object> ()
Gen<string>.foo<string,object> ()
Ban<string>.foo<string,object> ()
The MRGCTX contains, apart from the RGCTX-like slots, two items of data: A pointer to the vtable of the method’s class, and the values of the method’s type arguments. The first one is needed to get to the class’s RGCTX if no this argument is passed, i.e. in static generic methods. The type arguments are needed to instantiate new slots in the MRGCTX – without knowing what the value of T is, for example, we cannot look up the type Dictionary<S,T>.
So how much memory do we save with shared generic methods? In my previous post on sharing generic code I presented a table with the savings in memory my three large test applications. Here it is again, updated with data for sharing generic methods:
No sharing
Sharing
Sharing w/gen methods
Methods
compiledCode
producedMethods
compiledCode
producedMethods
compiledCode
producedMemory for
(M)RGCTXsSavings
IronPython
3614
719k
3368
691k
3324
687k
7k
25k
Nemerle
7210
2001k
6302
1943k
6150
1891k
34k
76k
F#
15529
2193k
11431
2062k
9823
1652k
154k
387k
Note that this time I’m also counting all the memory used by (M)RGCTXs and the (M)RGCTX templates, which I didn’t do last time.




This is fascinating. I wish I knew more about generics and how they are compiled. I will have to read more of your blog :)
Comment by Sam — June 5, 2008 @ 11:52 pm
[...] Filed under: Software — by schani @ 7:37 pm Tags: generics, mono, types Since my last report on generic code sharing I chased down a few bugs we uncovered when trying out IronPython 2.0. That [...]
Pingback by Another Generic Sharing Update « Juggling, Photography, Software, and Atheism — June 27, 2008 @ 7:37 pm