[runtime] Move caches from Images to ImageSets if their keys contain generic types
authorAlexander Kyte <alexander.kyte@xamarin.com>
Wed, 6 May 2015 21:56:11 +0000 (17:56 -0400)
committerRodrigo Kumpera <kumpera@gmail.com>
Tue, 28 Jul 2015 05:26:18 +0000 (01:26 -0400)
commitbd6c263cdca1a4f9a50c3dfd267ef78534ec806c
treeac4328db3f8ef1875df88a41f60580e09070e21f
parent12e265cda639961fffa9dd25c61f3f3ec6ce9f00
[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.
mono/metadata/class-internals.h
mono/metadata/image.c
mono/metadata/marshal.c
mono/metadata/metadata-internals.h
mono/metadata/metadata.c