Treat byref-typed uses of int-typed lclVars as type int in LB.
authorPat Gavlin <pagavlin@microsoft.com>
Tue, 25 Jul 2017 22:43:05 +0000 (15:43 -0700)
committerPat Gavlin <pagavlin@microsoft.com>
Tue, 25 Jul 2017 22:47:27 +0000 (15:47 -0700)
commit3a1fe1c959f7820d006e59bf9da0d5278168cc97
tree07577882623687bbdd888f52d8a96ab2cf46e137
parentdd1e7ab81221127e47d59052c51c09921007d607
Treat byref-typed uses of int-typed lclVars as type int in LB.

This is consistent with the behvaior of both JIT32 and RyuJIT. This
resolves an assertion originating from the following scenario:

1. The input IL contains a lclVar of type `Foo*`, which the JIT imports as
   `TYP_I_IMPL` (which is `TYP_INT` in this case).
2. This lclVar is used as the `this` argument to a number of method calls.
   This is legal as per ECMA-335 section III.3.19 ("Correct CIL also allows
   a native int to be passed as a byref (&); in which case following the
   store the value will be tracked by garbage collection.")
3. All of the method calls to which this lclVar is passed as a byref are
   inlined. This produces many uses of the lclVar as a byref (i.e. we see
   nodes like `lclVar V06 byref` even though V06's varDsc has type int).
4. The lclVar is assigned a register `r`. At its first appearance--which is
   the first occasion in which it is loaded into this register--it is used
   as `TYP_BYREF`. When the code generator processes this appearance, it
   first sets the appropriate bit for `r` in `gcInfo.gcRegByrefSetCur`
   (`gcInfo.gcMarkRegPtrVal`, called by `genCodeForTree_REG_VAR1`) and then
   sets the appropriate bit for `r` in `regSet.rsMaskVars`
   (`genUpdateLife`).
5. The lclVar is used as `TYP_INT` as the operand to a `GT_RETURN` node.
   When the code generator processes this appearance, it attempts to update
   the GC-ness of `r` by calling `gcInfo.gcMarkRegPtrVal` (again via
   `genCodeForTree_REG_VAR1`). This function, though, explicitly excludes
   registers that contain live variables from its update, so `r` remains in
   `gcInfo.gcRegByrefSetCur` after this call. After calling
   `gcMarkRegPtrVal`, `genCodeForTree_REG_VAR1` calls `genUpdateLife`,
   which removes the the lclVar from `regSet.rsMaskVars`.
6. An assertion intended to verify that the only registers that are live
   after processing a statement are registers that contain lclVars fires,
   as `gcRegByrefSetCur` still contains `r`.

Fixes VSO 468732.
src/jit/codegenlegacy.cpp
tests/src/JIT/Regression/JitBlue/DevDiv_468732/DevDiv_468732.cs [new file with mode: 0644]
tests/src/JIT/Regression/JitBlue/DevDiv_468732/DevDiv_468732.csproj [new file with mode: 0644]