Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Purpose of TypeDependencyAttribute("System.SZArrayHelper") for IList<T>, IEnumerable<T> and ICollection<T>?

Tags:

c#

.net

The comments provided in the source code for IList, IEnumerable and ICollection says

Note that T[] : IList<T>, and we want to ensure that if you use IList<YourValueType>, we ensure a YourValueType[] can be used without jitting. Hence the TypeDependencyAttribute on SZArrayHelper. This is a special hack internally though - see VM\compile.cpp.

Why does IList<T> contain a dependency on SZArrayHelper?. I understand that SZArrayHelper is a CLR wrapper around an array that implements the IList<T> interface but I do not get the full picture of why these two are tied together.

And how does it ensure YourValueType[] can be used without jitting.?

like image 462
NullReference Avatar asked Nov 10 '15 14:11

NullReference


1 Answers

It's a hack in the JIT, as noted in your quote. When the VM finds that there's a TypeDependency on SZArrayHelper, it treats the class differently, allowing more efficient code to be used.

Looking at the relevant code in the VM (note that I'm using an older, public version here - not the actual .NET VM):

A call to an array thru IList (or IEnumerable or ICollection) has to be handled specially. These interfaces are "magic" (mostly due to working set concerned - they are created on demand internally even though semantically, these are static interfaces.)

Arrays are a bit of a hack in .NET in the first place. When the generic interfaces were added, this posed a bit of a problem - for example, int[] is an Array, but it is also a special type, and array of int; this allowed arrays to be generic before real generic types were added.

Now, let's see a concrete example. You have an int[], and you want to use it in LINQ. Since int[] implements IEnumerable<int>, it gives you the full power of LINQ out of the box, and you can write something like this:

var positiveNumbers = numbers.Where(i => i > 0);

From C#'s point of view, there is no problem. However, from the point of the internals of the VM, this is a big problem, because int[] doesn't actually implement IEnumerable<int>! Even after introducing generics to .NET (and C#), arrays are still handled the old way.

The hack is to use SZArrayHelper to handle any of those generic methods. So, for example, Where calls GetEnumerator internally on the IEnumerable<int>. The VM finds out that you're trying to call GetEnumerator on an array, and instead of virtually dispatching GetEnumerator on the array instance, it redirects the call to SZArrayHelper.GetEnumerator<int>().

This is a huge hack - if you look at the reference code for SZArrayHelper, you'll find tons of warnings - for example, the GetEnumerator<int> method is an instance method, but it's this argument is actually the array (e.g. int[]), not SZArrayHelper.

But it allows us to treat arrays as if they did actually implement all those generic interfaces - even though they don't :)

like image 58
Luaan Avatar answered Nov 01 '22 05:11

Luaan