Incorrect constrained virtual call in method using gsharedvt for reference type....
commit0db52289a39cf21618ec604f2b0940bbfbfd616b
authorJohan Lorensson <lateralusx.github@gmail.com>
Thu, 10 Oct 2019 13:22:54 +0000 (10 15:22 +0200)
committerZoltan Varga <vargaz@gmail.com>
Thu, 10 Oct 2019 13:22:54 +0000 (10 09:22 -0400)
tree06c6331eae54ae8803a8e44dbc719cbe2804a90f
parent6ebf07f2cd4f71218c6a4a2ed5f855a5ac9ce9e3
Incorrect constrained virtual call in method using gsharedvt for reference type. (#17227)

* Incorrect constrained virtual call in method using gsharedvt for reference type.

For generic constrained virtual calls using reference type's, the
virtual call will be dispatched using instance vtable. When the same
virtual call is taking place in a gsharedvt method, mono_gsharedvt_constrained_call
gets called that will assist making the call, the problem is that it will
use the constrained class for reference types meaning that it will not call
the most derived implementation of the method. This difference in the behavior
compared to none gsharedvt versions of methods, gives inconsistent results.

One way this will reproduce is by using Dictionary<Type, EmptyStruct>. For
methods that will take both Type (reference type) and EmptyStruct (value type)
like Add, calling that through IDictionary (hiding details from compiler) will
use the gsharedvt version of the method. Internally that method will call
Type.GetHashCode (), and since Type really is a RuntimeType it overrides
GetHashCode. But since mono_gsharedvt_constrained_call will use the constrained
class instead of the instance class, the called method will be
Object.GetHashCode, that gives a different result. When later ContainsKey
is called using the same Type, it only takes a reference value, so not
using a gsharedvt version of the method, then the most derived version of
GetHashCode will be called, given a different hash, not finding item
in dictionary.

Fix is to make sure behavior in mono_gsharedvt_constrained_call match
behavior for regular constrained virtual calls when having a reference type.
This makes sure we always call the most derived version of the method.

Commit also adds a test for this specific scenario using a dictionary.

* Updated to a more low-level test.
mono/mini/gshared.cs
mono/mini/jit-icalls.c