【问题标题】:How local variable usage infomation is maintained in .net clr source code.net core 源代码中如何维护局部变量使用信息
【发布时间】:2015-08-05 15:31:00
【问题描述】:

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

在将方法的 IL 编译为机器代码时,抖动执行两个重要任务。 ... 它还会生成一个表,描述如何使用方法体内的局部变量。 该表为每个方法参数和具有两个地址的局部变量都有一个条目。变量将首先存储对象引用的地址。以及不再使用该变量的机器代码指令的地址。 ... 表中“不再使用”的地址非常重要。它使垃圾收集器非常高效。它可以收集对象引用,即使它在方法内部使用并且该方法尚未完成执行

我很好奇 JIT 创建的内部表是什么样子的,以及在真正的 clr 源代码中如何维护“不再使用”的地址。谁能给我看一下最近开源的coreclr source code中的相关代码sn-ps?

【问题讨论】:

    标签: .net garbage-collection clr jit


    【解决方案1】:

    免责声明:我不是 CLR 或 RyuJIT 方面的专家。我可能完全错了。

    我在Book of the RuntimeRyuJIT chapter中遇到了以下section

    对于具有跟踪生命周期的 lvlVar,或者对于涉及 GC 引用的表达式,我们会报告引用的有效范围。这是由发射器完成的,发射器将此信息添加到指令组,并在 GC 信息更改时终止指令组。

    可以在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
    };
    

    我上面引用的段落表明这些字段由“发射器”填充,我相信它们的意思是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()

    如果您想进一步探索,希望这将成为一个起点。

    【讨论】:

    • 很好的答案,谢谢!现在我只想大致了解它在真正的 clr 源代码中的样子。也许有一天我会尝试深入阅读和学习 clr 源代码。 :P
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多