[runtime] Move caches from Images to ImageSets if their keys contain generic types
We currently have a partial ordering of dependencies between ImageSets and images.
If you free an image that an ImageSet depends on, you must free the
ImageSet. The inverse is not true. Freeing the ImageSet does not free
any images.
We had some caches in each Image which used method signatures as keys.
When an image signature refers to a type stored in an ImageSet, and that
ImageSet has been unloaded, the signature will remain in the cache for
the Image.
When we have another object hash to the same slot as this signature, we
must check if the two signatures are actually equal, that is if they are
equal keys or a hash collision. In this check we will refer to the
MonoType in the freed ImageSet.
By moving the caches containing inflated type references into the ImageSets
holding these inflated types, we ensure that the cache items are always safe
to dereference.
Why not simply remove the signatures from all caches they contain on
freeing the signature? This is much more work. A signature with a dozen
type parameters in a dozen images may have been used as a key in any of these
images. We would have to check all caches in all images the signature
refers to. As these caches use open addressing, in the worst time this
can take
```
(# images in signature) x (# caches per image) x (# of slots traversed on average)
```
steps. By placing it on the ImageSet, this takes only the steps required
to free a hash table. It is also easier to reason about.
Changes by Rodrigo Kumpera:
Added locking comments to the new fields in MonoImageSet.
Fixed the selected cache in mono_marshal_get_delegate_begin_invoke, mono_marshal_get_delegate_end_invoke,
mono_marshal_get_delegate_invoke_internal and mono_marshal_get_synchronized_wrapper.
The original code was using the image set of the class instead of the IS of the inflated method. This would
pick the wrong image if the method belonged to a different IS.