Skip to content

Add return value variable homes#128397

Open
noahfalk wants to merge 1 commit into
dotnet:mainfrom
noahfalk:return_value_homes
Open

Add return value variable homes#128397
noahfalk wants to merge 1 commit into
dotnet:mainfrom
noahfalk:return_value_homes

Conversation

@noahfalk
Copy link
Copy Markdown
Member

Historically we've used CALL_INSTRUCTION source mapping entries to imply return value homes for IL call instructions. That encoding requires debuggers to embed architecture specific disassembly and ABI logic to infer the where the return value is live and where it will be stored. Adding an explicit return value home shifts that responsibility to the code generator in exchange for making the encoded data slightly larger (likely 2-3 extra nibbles per callsite). We only expect this data to be produced for debug code.

@kotlarmilos @matouskozak @jakobbotsch @AndyAyersMS @jkotas @davidwrighton @dotnet/dotnet-diag
Following up from my comment on #127760 - this is a strawman design for how we could adjust the debug info contract. I wanted to get feedback if folks like the direction as well as this particular way of encoding it. If we keep going in this direction I imagine we'd:

  1. Add support for parsing the new return value home data to DBI (temporarily in parallel to the CALL_INSTRUCTION encoding)
  2. Add support in interpreter + JIT to emit the new homes instead of CALL_INSTRUCTION mappings.
  3. Once everything is working, remove the unneeded CALL_INSTRUCTION handling in DBI.

Historically we've used CALL_INSTRUCTION source mapping entries to imply return value homes for IL call instructions.
That encoding requires debuggers to embed architecture specific disassembly and ABI logic to infer the where the return value is live and
where it will be stored. Adding an explicit return value home shifts that responsibility to the code generator in exchange for making
the encoded data slightly larger (likely 2-3 extra nibbles per callsite). We only expect this data to be produced for debug code.
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/runtime-infrastructure
See info in area-owners.md if you want to be subscribed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the DebugInfo data contract design document to describe an explicit encoding for “call return value homes” in the Vars stream, instead of relying on CALL_INSTRUCTION source mappings and ABI inference in debuggers.

Changes:

  • Extends the documented DebugVarInfo shape with a ReturnValueILOffset field.
  • Introduces a CALL_RETURN_ILNUM sentinel var number and updates the documented var-number bias constant.
  • Updates the Vars nibble encoding to conditionally interpret field #2 as either endOffsetDelta or returnValueILOffset.

public uint StartOffset { get; init; }
public uint EndOffset { get; init; }
public uint VarNumber { get; init; }
public uint ReturnValueILOffset { get; init; }
Comment on lines +356 to +357
| `MAX_ILNUM` | Bias for adjusted encoding of variable numbers | `0xfffffffb` (-5) |
| `CALL_RETURN_ILNUM` | A sentinel variable number indicating this variable home stores a call return value | `0xfffffffb` (-5) |
Comment on lines 374 to 382
Each variable entry in the Vars section is nibble-encoded as follows:

1. `startOffset` — encoded unsigned 32-bit integer
2. `endOffset` — encoded as delta from `startOffset` (unsigned)
2. `endOffset` or `returnValueILOffset` depending on the following `varNumber`

If varNumber == CALL_RETURN_ILNUM: `returnValueILOffset` encoded as unsigned 32-bit integer. `EndOffset` is implicitly `StartOffset+1`. `ReturnValueILOffset` identifies the offset of the IL call instruction whose return value is stored in this home.
If varNumber != CALL_RETURN_ILNUM: `endOffset` encoded as delta from `startOffset` (unsigned). `ReturnValueILOffset` is implicitly zero though it is unused and meaningless in this case.

3. `varNumber` — encoded as adjusted unsigned (`value - MAX_ILNUM`)
@jkotas
Copy link
Copy Markdown
Member

jkotas commented May 20, 2026

That encoding requires debuggers to embed architecture specific disassembly and ABI logic to infer the where the return value is live and where it will be stored.

How is this done in C/C++ debugger? Does the debugger embed architecture specific details, or is the home encoded in debug info?

@noahfalk
Copy link
Copy Markdown
Member Author

How is this done in C/C++ debugger? Does the debugger embed architecture specific details, or is the home encoded in debug info?

My understanding is C/C++ debuggers, if they support the feature at all, do it by embedding all the architecture knowledge and reverse engineering it from the assembly. They can use the PDB to lookup function return type information but the rest would be calculated using disassembly and known ABIs.

.NET could implement it that way too but IMO it pushes an unnecessary amount of detail into the data contract.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants