JIT: change codgen for dup to not lose type information
The jit has traditionally optimized most cases of a
zz; dup; stloc.x
sequence into
zz; stloc.x; ldloc.x
with a comment noting that this makes the resulting compiler IR
more amenable to CSE. Here zz is any IL operation that pushes
a value on the stack. However if zz's result is a ref type, the
dup'ed value produced by zz may be a subtype of the type of the
local x, so this transformation can lose type information.
In the past the loss of type information hasn't mattered, but now if
zz subsequently is used as the this object in a virtual call, the jit
may attempt devirtualization and ask an ill-posed question to the VM,
claiming the type of the this object is an impossible supertype.
This changes modifies the transformation by introducing a new local temp y
that has the type of zz. The result is now
zz; stloc.y; ldloc.y; ldloc.y; stloc.x
with the net result that a ldloc.y is left on the stack with the proper
type. As an optimization, if zz is ldloc.z then the expansion is simply
zz (ldloc.z); ldloc.z; stloc.y
and if zz is a simple "cheap" constant (say ldnull) then the constant
expression is duplicated:
zz (ldnull); ldnull; stloc.y
This resolves the jit side of dotnet/coreclr#9945. Further work is needed on the VM
side since in unverifiable IL there may be other cases where the jit
can present an impossible type.
Diffs from this were minor and in many cases small improvements.
Commit migrated from https://github.com/dotnet/coreclr/commit/
743e5e1660b308cba660565419a972146a6b4191