.net core源码中如何维护局部变量使用信息

How local variable usage infomation is maintained in .net clr source code

This great answer 解释了 GC 如何能够在方法完成执行之前收集局部变量:

The jitter performs two important duties when it compiles the IL for a method into machine code. ... It also generates a table that describes how the local variables inside the method body are used. That table has an entry for each method argument and local variable with two addresses. The address where the variable will first store an object reference. And the address of the machine code instruction where that variable is no longer used. ... The "no longer used" address in the table is very important. It makes the garbage collector very efficient. It can collect an object reference, even if it is used inside a method and that method hasn't finished executing yet.

我很好奇 JIT 如何创建内部表,以及 "no longer used" 地址是如何在 真正的 clr 源代码 中维护的。谁能给我看看最近开源的coreclr source code?

中的相关代码片段

免责声明:我不是 CLR 或 RyuJIT 方面的专家。关于这一切,我可能完全错了。

我遇到了以下 section in the RyuJIT chapter of the Book of the Runtime

For lvlVars with tracked lifetimes, or for expression involving GC references, we report the range over which the reference is live. This is done by the emitter, which adds this information to the instruction group, and which terminates instruction groups when the GC info changes.

可以在 jit/jitgcinfo.h 中找到存储此信息的结构,如下所示:

struct varPtrDsc
{
    varPtrDsc   *   vpdNext;

    unsigned        vpdVarNum;         // which variable is this about?

    unsigned        vpdBegOfs ;        // the offset where life starts
    unsigned        vpdEndOfs;         // the offset where life starts
};

我上面引用的段落表明这些字段由 "the emitter" 填充,我认为它们的意思是 jit/emit.cpp

生命周期的开始时间设置在emitter::emitGCvarLiveSet();相关摘录是(为简洁起见删除了空白):

/* Allocate a lifetime record */
desc = new (emitComp, CMK_GC) varPtrDsc;
desc->vpdBegOfs = emitCurCodeOffs(addr);
#ifdef DEBUG
desc->vpdEndOfs = 0xFACEDEAD;
#endif
desc->vpdVarNum = offs;
desc->vpdNext = NULL;

生命周期的结束以类似的方式设置,在 emitter::emitGCvarDeadSet():

/* Record the death code offset */
assert(desc->vpdEndOfs == 0xFACEDEAD);
       desc->vpdEndOfs  = emitCurCodeOffs(addr);

最后,表格似乎是用 jit/gcencode.cpp 写的,特别是 GCInfo::gcMakeVarPtrTable()

如果您想进一步探索,希望这可以作为一个起点。